Mixin是什么概念?
在浏览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 类本身不是 is-a 的关系,混入 Mixin 类是为了添加某些(可选的)功能。自由地混入 Mixin 类就可以灵活地为被混入的类添加不同的功能。
传统的「接口」概念中并不包含实现,而 Mixin 包含实现。实际上 Mixin 的作用和 Java 中的众多以「able」结尾的接口很相似。不同的是 Mixin 提供了(默认)实现,而 Java 中实现了 -able 接口的类需要类自身来实现这些混入的功能(Serializable 接口是个例外)。 趁着午休来答一个。
如楼上很多答主一样,谈到Mixin就不得不谈到多重继承,因为Mixin的出现就是为了解决多重继承的问题,那么多重继承有什么问题呢?
在《松本行弘的程序世界》一书中,作者列举了以下三点:
- 结构复杂化:如果是单一继承,一个类的父类是什么,父类的父类是什么,都很明确,因为只有单一的继承关系,然而如果是多重继承的话,一个类有多个父类,这些父类又有自己的父类,那么类之间的关系就很复杂了。
- 优先顺序模糊:假如我有A,C类同时继承了基类,B类继承了A类,然后D类又同时继承了B和C类,所以D类继承父类的方法的顺序应该是D、B、A、C还是D、B、C、A,或者是其他的顺序,很不明确。
- 功能冲突:因为多重继承有多个父类,所以当不同的父类中有相同的方法是就会产生冲突。如果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 技术按一下规则来限制多重继承:
- 继承用但一继承;
- 第二个及两个以上的父类必须是 Mix-in 的抽象类。
Mix-in 类是具有以下特征的抽象类:
- 不能单独生成实例;
- 不能继承普通类。
按照以上的原则,类在层次上具有单一继承一样的树结构,同时又可以实现功能的共享(方法是:把共享的功能放在 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类,需要满足以下条件:
- 不能单独生成实例对象,属于抽象类。
- 不能继承Mixin以外的类。
Java的接口,只提供了“规格”的多重继承。Mixin类则同时提供了“规格”和“实现”的多重继承,使用上相比接口会更加简单。

热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

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

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

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

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

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

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

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

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