目次
回复内容:

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 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

PHP と OAuth: Microsoft ログイン統合の実装 PHP と OAuth: Microsoft ログイン統合の実装 Jul 28, 2023 pm 05:15 PM

PHP と OAuth: Microsoft ログイン統合の実装 インターネットの発展に伴い、便利な登録とログイン エクスペリエンスを提供するために、ユーザーがサードパーティ アカウントを使用してログインできるようにする必要がある Web サイトやアプリケーションがますます増えています。 Microsoft アカウントは世界中で広く使用されているアカウントの 1 つであり、多くのユーザーが Web サイトやアプリケーションにログインするために Microsoft アカウントを使用したいと考えています。 Microsoft ログインの統合を実現するには、OAuth (Open Authorization) プロトコルを使用します。 OAuth は、ユーザーがサードパーティのアプリケーションに代わって動作することを承認できるオープン標準の承認プロトコルです。

PHP 開発: Laravel Passport を使用した OAuth2 サービス プロバイダーの実装 PHP 開発: Laravel Passport を使用した OAuth2 サービス プロバイダーの実装 Jun 15, 2023 pm 04:32 PM

モバイル インターネットの普及に伴い、ユーザーが自分自身を認証し、許可することを必要とするアプリケーションがますます増えています。 OAuth2 は、これらの機能を実装するための標準化されたメカニズムをアプリケーションに提供する、一般的な認証および認可フレームワークです。 LaravelPassport は、使いやすく安全ですぐに使える OAuth2 サーバー実装であり、PHP 開発者に OAuth2 認証と認可を構築するための強力なツールを提供します。この記事ではLaravelPassportの使い方を紹介します。

PHP と OAuth を使用して Google ドライブを統合する方法 PHP と OAuth を使用して Google ドライブを統合する方法 Jul 31, 2023 pm 04:41 PM

PHP と OAuth を使用して GoogleDrive を統合する方法 GoogleDrive は、ユーザーがクラウドにファイルを保存し、他のユーザーと共有できるようにする人気のクラウド ストレージ サービスです。 GoogleDriveAPI を通じて、PHP を使用して GoogleDrive と統合するコードを記述し、ファイルのアップロード、ダウンロード、削除、その他の操作を実装できます。 GoogleDriveAPI を使用するには、OAuth 経由で認証する必要があります。

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 で CRUD (追加、削除、変更、確認) 操作を実装するためのヒント ミックスインを使用して Vue で CRUD (追加、削除、変更、確認) 操作を実装するためのヒント Jun 25, 2023 pm 07:42 PM

Vue の Mixin は非常に便利な機能で、再利用可能なコードを mixin オブジェクトにカプセル化し、mixin を使用してこれらのコードを使用する必要があるコンポーネントにコードを導入できます。この方法により、特に繰り返し行われる CRUD (追加、削除、変更) 操作において、コードの再利用性と保守性が大幅に向上します。この記事では、ミックスインを使用して Vue で CRUD 操作を実装する方法を紹介します。まず、作成方法を理解する必要があります。

OAuth2認証方式とPHPでの実装 OAuth2認証方式とPHPでの実装 Aug 07, 2023 pm 10:53 PM

OAuth2 認証方法と PHP での実装 インターネットの発展に伴い、サードパーティのプラットフォームと対話する必要があるアプリケーションがますます増えています。ユーザーのプライバシーとセキュリティを保護するために、多くのサードパーティ プラットフォームは OAuth2 プロトコルを使用してユーザー認証を実装しています。この記事では、OAuth2 認証方法と PHP での実装を紹介し、対応するコード例を添付します。 OAuth2 は、ユーザーがサードパーティのアプリケーションが別のサービス プロバイダー上のリソースにアクセスすることを、何も言及せずに承認できるようにする承認フレームワークです。

QQ ログイン統合に PHP と OAuth を使用する方法 QQ ログイン統合に PHP と OAuth を使用する方法 Jul 31, 2023 pm 12:37 PM

QQ ログイン統合に PHP と OAuth を使用する方法の紹介: ソーシャル メディアの発展に伴い、ユーザーが簡単に登録してログインできるように、サードパーティのログイン機能を提供する Web サイトやアプリケーションが増えています。中国最大のソーシャル メディア プラットフォームの 1 つである QQ は、多くの Web サイトやアプリケーションで提供されるサードパーティのログイン サービスとしても利用されています。この記事では、QQ ログイン統合に PHP と OAuth を使用する方法の手順をコード例とともに紹介します。ステップ 1: QQ オープン プラットフォーム開発者として登録します。QQ ログインの統合を開始する前に、

NotImplementedError() の解決策 NotImplementedError() の解決策 Mar 01, 2024 pm 03:10 PM

エラーの原因は Python にあり、Tornado で NotImplementedError() がスローされるのは、抽象メソッドまたはインターフェイスが実装されていないことが原因である可能性があります。これらのメソッドまたはインターフェイスは親クラスで宣言されますが、子クラスでは実装されません。サブクラスが適切に動作するには、これらのメソッドまたはインターフェイスを実装する必要があります。この問題を解決するには、親クラスで宣言した抽象メソッドやインターフェイスを子クラスに実装します。別のクラスから継承するクラスを使用していてこのエラーが発生した場合は、親クラスで宣言されたすべての抽象メソッドを子クラスに実装する必要があります。インターフェイスを使用していてこのエラーが発生した場合は、インターフェイスで宣言されているすべてのメソッドを、インターフェイスを実装するクラスに実装する必要があります。どちらかわからない場合は、

See all articles