目录
回复内容:
首页 后端开发 Python教程 Mixin是什么概念?

Mixin是什么概念?

Jun 06, 2016 pm 04:23 PM
auth mixin oauth openid tornado

在浏览tornado的代码时,auth中的类都以Mixin命名,这个词好奇怪啊,查了一下资料,有人解释Mixin为mix in,混入的意思,类似于多重继承。auth模块实现OpenID和OAuth,为什么要用Mixin方式?Mixin的应用场景?与“接口”概念有什么区别?

回复内容:

Mixin 实质上是利用语言特性(比如 Ruby 的 include 语法、Python 的多重继承)来更简洁地实现组合模式

以如下 Java 伪码为例,实现一个可复用的“打标签”组件(Taggable),并且应用到帖子(Post)模型上:
<span class="kn">import</span> <span class="nn">java.util.List</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.ArrayList</span><span class="o">;</span>

<span class="kd">interface</span> <span class="nc">Entity</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getId</span><span class="o">();</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getKind</span><span class="o">();</span>
<span class="o">}</span>

<span class="kd">interface</span> <span class="nc">Taggable</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addTag</span><span class="o">(</span><span class="kt">int</span> <span class="n">tagId</span><span class="o">);</span>
    <span class="kd">public</span> <span class="n">List</span><span class="o"><</span><span class="n">Integer</span><span class="o">></span> <span class="nf">getTags</span><span class="o">();</span>
<span class="o">}</span>

<span class="kd">class</span> <span class="nc">TaggableImpl</span> <span class="kd">implements</span> <span class="n">Taggable</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="n">Entity</span> <span class="n">target</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">TaggableImpl</span><span class="o">(</span><span class="n">Entity</span> <span class="n">target</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">target</span> <span class="o">=</span> <span class="n">target</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addTag</span><span class="o">(</span><span class="kt">int</span> <span class="n">tagId</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="n">target</span><span class="o">.</span><span class="na">getId</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">kind</span> <span class="o">=</span> <span class="n">target</span><span class="o">.</span><span class="na">getKind</span><span class="o">();</span>
        <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"insert into ... values "</span>
                <span class="o">+</span> <span class="n">id</span> <span class="o">+</span> <span class="s">", "</span>
                <span class="o">+</span> <span class="n">kind</span> <span class="o">+</span> <span class="s">", "</span>
                <span class="o">+</span> <span class="n">tagId</span> <span class="o">+</span> <span class="s">")"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="n">ArrayList</span><span class="o"><</span><span class="n">Integer</span><span class="o">></span> <span class="nf">getTags</span><span class="o">()</span> <span class="o">{</span>
        <span class="c1">// query from database</span>
        <span class="k">return</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o"><</span><span class="n">Integer</span><span class="o">>();</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">class</span> <span class="nc">Post</span> <span class="kd">implements</span> <span class="n">Entity</span><span class="o">,</span> <span class="n">Taggable</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">final</span> <span class="kd">static</span> <span class="kt">int</span> <span class="n">KIND</span> <span class="o">=</span> <span class="mi">1001</span><span class="o">;</span>

    <span class="kd">private</span> <span class="n">Taggable</span> <span class="n">taggable</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kt">int</span> <span class="n">id</span><span class="o">;</span>
    <span class="kd">private</span> <span class="n">String</span> <span class="n">title</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">Post</span><span class="o">(</span><span class="kt">int</span> <span class="n">id</span><span class="o">,</span> <span class="n">String</span> <span class="n">title</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">id</span> <span class="o">=</span> <span class="n">id</span><span class="o">;</span>
        <span class="k">this</span><span class="o">.</span><span class="na">title</span> <span class="o">=</span> <span class="n">title</span><span class="o">;</span>
        <span class="k">this</span><span class="o">.</span><span class="na">taggable</span> <span class="o">=</span> <span class="k">new</span> <span class="n">TaggableImpl</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getId</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">id</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getKind</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">KIND</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addTag</span><span class="o">(</span><span class="kt">int</span> <span class="n">tagId</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">taggable</span><span class="o">.</span><span class="na">addTag</span><span class="o">(</span><span class="n">tagId</span><span class="o">);</span>  <span class="c1">// delegate</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="n">ArrayList</span><span class="o"><</span><span class="n">Integer</span><span class="o">></span> <span class="nf">getTags</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">taggable</span><span class="o">.</span><span class="na">getTags</span><span class="o">();</span>  <span class="c1">// delegate</span>
    <span class="o">}</span>
<span class="o">}</span>
登录后复制
Mixin 就是混入的意思。

和多重继承类似(其实可以把 Mixin 看作多重继承的一种在特定场景下的应用),但通常混入 Mixin 的类和 Mixin 类本身不是 is-a 的关系,混入 Mixin 类是为了添加某些(可选的)功能。自由地混入 Mixin 类就可以灵活地为被混入的类添加不同的功能。

传统的「接口」概念中并不包含实现,而 Mixin 包含实现。实际上 Mixin 的作用和 Java 中的众多以「able」结尾的接口很相似。不同的是 Mixin 提供了(默认)实现,而 Java 中实现了 -able 接口的类需要类自身来实现这些混入的功能(Serializable 接口是个例外)。 趁着午休来答一个。

如楼上很多答主一样,谈到Mixin就不得不谈到多重继承,因为Mixin的出现就是为了解决多重继承的问题,那么多重继承有什么问题呢?

在《松本行弘的程序世界》一书中,作者列举了以下三点:

  1. 结构复杂化:如果是单一继承,一个类的父类是什么,父类的父类是什么,都很明确,因为只有单一的继承关系,然而如果是多重继承的话,一个类有多个父类,这些父类又有自己的父类,那么类之间的关系就很复杂了。
  2. 优先顺序模糊:假如我有A,C类同时继承了基类,B类继承了A类,然后D类又同时继承了B和C类,所以D类继承父类的方法的顺序应该是D、B、A、C还是D、B、C、A,或者是其他的顺序,很不明确。
  3. 功能冲突:因为多重继承有多个父类,所以当不同的父类中有相同的方法是就会产生冲突。如果B类和C类同时又有相同的方法时,D继承的是哪个方法就不明确了,因为存在两种可能性。
当然你可以说有些语言解决了这个问题,但是并不是所有语言都想要去纠结这个问题。

所以为能够利用多继承的优点又解决多继承的问题,提出了规格继承和实现继承这两样东西。

简单来讲,规格继承指的是一堆方法名的集合,而实现继承除了方法名还允许有方法的实现。

Java 选择了规格继承,在 Java 中叫 interface(不过Java8中已经有默认方法了),而 Ruby 选择了实现继承,也可以叫Mixin,在 Ruby 中叫 module。

从某种程度上来说,继承强调 I am,Mixin 强调 I can。当你 implement 了这个接口或者 include 这个 module 的时候,然后就你行你上。

所以这又可以扯到 duck typing 去了,不细说。要想了解具体的可以看一下《松本行弘的程序世界》这本书。 这叫迷信方法,你想知道好处,打开py源码,搜搜 mixin,试着不用迷信实现一个本来用了迷信的模块,就能切身感受一下了。 为了解决多重继承的问题,Java引入了接口 (interface)技术Lisp、Ruby引入了 Mix-in 技术。


以 Ruby 为例,Mix-in 有效地降低多重继承复杂性(谁是你爹,哪个爹的优先级高,你的把妹方法是继承自哪个爹的等)。 Ruby中 Mix-in 的单位是 模块 (module)

Mix-in 技术按一下规则来限制多重继承:
  1. 继承用但一继承;
  2. 第二个及两个以上的父类必须是 Mix-in 的抽象类。

Mix-in 类是具有以下特征的抽象类:
  1. 不能单独生成实例;
  2. 不能继承普通类。

按照以上的原则,类在层次上具有单一继承一样的树结构,同时又可以实现功能的共享(方法是:把共享的功能放在 Mix-in 类中,再把 Mix-in 类插入到树结构里)。

Java 用 接口 解决规格继承(类都有哪些方法)的问题,Mix-in 则解决了实现继承(类中都用了什么数据结构和什么算法)的问题。

逼逼了这么多,对于 Mix-in 的理解是,Mix-in 只不过是实现多重继承的一个技巧而已。 被约束的多重继承。 mixin不是多继承,mixin是duck type的糖,让你可以不用去把一坨坨Interface继承一遍然后才能彼此调用接口。mixin 并没有特别权威的标准,非要让我下个定论的话:mixin 其实就是在语言不提供标准多重继承的情况下,变相实现多重继承的一个语法糖。 不同版本的 mixin 实现不太一样,但出发点都是在允许继承接口和继承实现的基础上,简化继承关系,避免多重继承的坑。


我认为 C# 的扩展方法其实就是一种 mixin,但又不是通过代码拷贝等动态特性实现的,而是在编译器层面很严格的帮你进行了封装。对其它静态语言来说,如果没有多重继承,要自己实现 mixin 是很困难的。动态语言有些就支持 mixin,不支持的话自己造一个也很容易。


我最近也利用 javascript 实现了一个版本的 mixin 机制,为了支持可视化编辑,添加了类似组件系统的能力,将整合进 0.5 的 Fireball-x,到时会进一步更新答案。


手机码字求赞,欢迎更多讨论。 就是编译的时候把一段代码复制到另一个地方的意思。 Mixin是一种特殊的多重继承,也就是多重继承的子集。
使用Mixin的好处是,同时享有单一继承的单纯性和多重继承的共有性。

作为Mixin类,需要满足以下条件:
  1. 不能单独生成实例对象,属于抽象类。
  2. 不能继承Mixin以外的类。
因为有以上限制,Mixin类通常作为功能模块使用,在需要该功能时“混入”,而且不会使类的关系变得复杂(比如,同名方法到底从哪个父类继承)。
Java的接口,只提供了“规格”的多重继承。Mixin类则同时提供了“规格”和“实现”的多重继承,使用上相比接口会更加简单。
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

PHP和OAuth:实现微软登录集成 PHP和OAuth:实现微软登录集成 Jul 28, 2023 pm 05:15 PM

PHP和OAuth:实现微软登录集成随着互联网的发展,越来越多的网站和应用程序需要支持用户使用第三方账号登录,以提供方便的注册和登录体验。微软账号是全球范围内广泛使用的账号之一,许多用户希望使用微软账号登录网站和应用程序。为了实现微软登录集成,我们可以使用OAuth(开放授权)协议来实现。OAuth是一种开放标准的授权协议,允许用户授权第三方应用程序代表自己

如何使用PHP和OAuth进行Google Drive集成 如何使用PHP和OAuth进行Google Drive集成 Jul 31, 2023 pm 04:41 PM

如何使用PHP和OAuth进行GoogleDrive集成GoogleDrive是一款流行的云存储服务,它允许用户在云端存储文件并与其他用户共享。通过GoogleDriveAPI,我们可以使用PHP编写代码来与GoogleDrive进行集成,实现文件的上传、下载、删除等操作。要使用GoogleDriveAPI,我们需要通过OAuth进行身份验证并

PHP开发:使用 Laravel Passport 实现 OAuth2 服务提供者 PHP开发:使用 Laravel Passport 实现 OAuth2 服务提供者 Jun 15, 2023 pm 04:32 PM

随着移动互联网的普及,越来越多的应用程序都需要用户进行身份验证和授权。OAuth2是一种流行的认证和授权框架,它为应用程序提供了一种标准化的机制来实现这些功能。LaravelPassport是一个易于使用,安全且开箱即用的OAuth2服务器实现,它为PHP开发人员提供了构建OAuth2身份验证和授权的强大工具。本文将介绍LaravelPassport的使

PHP中的OAuth:创建一个JWT授权服务器 PHP中的OAuth:创建一个JWT授权服务器 Jul 28, 2023 pm 05:27 PM

PHP中的OAuth:创建一个JWT授权服务器随着移动应用和前后端分离的趋势的兴起,OAuth成为了现代Web应用中不可或缺的一部分。OAuth是一种授权协议,通过提供标准化的流程和机制,用于保护用户的资源免受未经授权的访问。在本文中,我们将学习如何使用PHP创建一个基于JWT(JSONWebTokens)的OAuth授权服务器。JWT是一种用于在网络中

Vue 中使用 mixin 实现 CRUD(增删改查)操作的技巧 Vue 中使用 mixin 实现 CRUD(增删改查)操作的技巧 Jun 25, 2023 pm 07:42 PM

Vue中的mixin是一个非常有用的特性,它可以将一些可重用的代码封装在一个mixin对象中,然后在需要使用这些代码的组件中使用mixin进行引入。这种方法大大提高了代码的可复用性和可维护性,特别是在一些重复的CRUD(增删改查)操作中。本文将介绍如何使用mixin在Vue中实现CRUD操作的技巧。首先,我们需要了解如何创建一个

PHP中的OAuth2鉴权方法及实现方式 PHP中的OAuth2鉴权方法及实现方式 Aug 07, 2023 pm 10:53 PM

PHP中的OAuth2鉴权方法及实现方式随着互联网的发展,越来越多的应用程序需要与第三方平台进行交互。为了保护用户的隐私和安全,许多第三方平台使用OAuth2协议来实现用户鉴权。在本文中,我们将介绍PHP中的OAuth2鉴权方法及实现方式,并附上相应的代码示例。OAuth2是一种授权框架,它允许用户授权第三方应用程序访问其在另一个服务提供商上的资源,而无需提

NotImplementedError()的处理方案 NotImplementedError()的处理方案 Mar 01, 2024 pm 03:10 PM

报错的原因在python中,Tornado中抛出NotImplementedError()的原因可能是因为未实现某个抽象方法或接口。这些方法或接口在父类中声明,但在子类中未实现。子类需要实现这些方法或接口才能正常工作。如何解决解决这个问题的方法是在子类中实现父类声明的抽象方法或接口。如果您正在使用一个类来继承另一个类,并且您看到了这个错误,则应该在子类中实现父类中所有声明的抽象方法。如果您正在使用一个接口,并且您看到了这个错误,则应该在实现该接口的类中实现该接口中所有声明的方法。如果您不确定哪些

如何使用PHP和OAuth进行QQ登录集成 如何使用PHP和OAuth进行QQ登录集成 Jul 31, 2023 pm 12:37 PM

如何使用PHP和OAuth进行QQ登录集成简介:随着社交媒体的发展,越来越多的网站和应用程序开始提供第三方登录功能,以方便用户快速注册和登录。QQ作为中国最大的社交媒体平台之一,也成为了许多网站和应用程序提供的第三方登录服务。本文将介绍如何使用PHP和OAuth进行QQ登录集成的步骤,并附带代码示例。步骤一:注册为QQ开放平台开发者在开始集成QQ登录之前,我

See all articles