ミックスインとは何ですか?なぜそれらが便利なのですか?


955

Programming Python」では、Mark Lutzが「mixins」について言及しています。私はC / C ++ / C#の出身ですが、以前にその用語を聞いたことがありません。ミックスインとは何ですか?

この例の行の間を読むと(非常に長いためにリンクしています)、「適切な」サブクラス化ではなく、多重継承を使用してクラスを拡張するケースであると思います。これは正しいですか?

新しい機能をサブクラスに入れるのではなく、なぜそれをしたいのですか?それについて、ミックスイン/マルチ継承アプローチがコンポジションを使用するよりも優れているのはなぜですか?

ミックスインと多重継承を区別するものは何ですか?それは単なる意味論の問題ですか?

回答:


710

ミックスインは特別な種類の多重継承です。ミックスインが使用される主な状況は2つあります。

  1. クラスに多くのオプション機能を提供したい。
  2. 多くの異なるクラスで1つの特定の機能を使用したい。

一番の例として、werkzeugの要求と応答システムを考えてみましょう。私は言うことによってプレーンな古いリクエストオブジェクトを作ることができます:

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

Acceptヘッダーのサポートを追加したい場合は、

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

Acceptヘッダー、etags、認証、ユーザーエージェントのサポートをサポートするリクエストオブジェクトを作成したい場合は、次のようにします。

from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin

class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
    pass

違いはわずかですが、上記の例では、ミックスインクラスが独自に作成されていません。より伝統的な多重継承では、AuthenticationMixin(たとえば)はおそらくのようなものになりAuthenticatorます。つまり、クラスはおそらくそれ自体で立つように設計されます。


123
3番目の状況は、クラスに多くの(オプションではない)機能を提供したいが、別々のクラス(および別々のモジュール)に機能を必要とするため、各モジュールは約1つの機能(動作)です。IOWではなく再利用のためですが、区画化のためです。
bootchk

60
この例ではおそらく問題ではありませんが、通常、メインの基本クラスを括弧内の最後の要素として置き、継承チェーンを作成します:Request ==> Mixin ==> ... ==> BaseRequest。こちらをご覧ください:ianlewis.org/en/mixins-and-python
hillel

10
@hillelは良い点ですが、Pythonはスーパークラスのメソッドを左から右に呼び出すことに注意してください(たとえば、コンストラクターをオーバーライドする必要がある場合)。
Eliseu Monar dos Santos 2015

9
これは、Decoratorデザインパターンのように聞こえます。
D-Jones

4
第四の状況は次のとおりです。そこの既存の家族既にあるParentクラスではとChild1Child2ChildNサードパーティのライブラリ内のサブクラス、あなたは全体の家族のためにカスタマイズされた振る舞いをします。理想的には、そのような動作をに追加しParent、サードパーティのライブラリ開発者がプルリクエストを受け取ることを望んでいます。そうしないとあなた自身を実装する必要がありますclass NewBehaviorMixinし、その後のようなラッパークラスのフルセットを定義class NewParent(NewBehaviorMixin, Parent): passしてclass NewChildN(NewBehaviorMixin, ChildN): pass、など(PS:あなたはより良い方法を知っていますか?)
RayLuo

240

まず、ミックスインは多重継承言語でのみ存在することに注意してください。JavaまたはC#ではミックスインを実行できません。

基本的に、ミックスインはスタンドアロンの基本型であり、子クラスに限られた機能と多態性の共鳴を提供します。C#で考えている場合は、既に実装されているため、実際に実装する必要のないインターフェイスを考えてください。あなたはそれから継承し、その機能性から利益を得るだけです。

ミックスインは通常、範囲が狭く、拡張することを意図していません。

[編集-理由について:]

あなたが尋ねたので、私は理由に対処する必要があると思います。大きなメリットは、何度も何度も自分で行う必要がないことです。C#では、ミックスインのメリットが最大になる可能性があるのは、Disposalパターンです。IDisposableを実装するときはいつでも、ほとんどの場合同じパターンに従いたいと思いますが、結局同じ基本コードを少し変更して書き直します。拡張可能なDisposalミックスインがあれば、余分な入力を大幅に省くことができます。

[編集2-他の質問に答える]

ミックスインと多重継承を区別するものは何ですか?それは単なる意味論の問題ですか?

はい。ミックスインと標準の多重継承の違いは、セマンティクスの問題です。複数の継承があるクラスは、その複数の継承の一部としてミックスインを利用する場合があります。

ミックスインのポイントは、継承タイプに影響を与えずに継承を介して他のタイプに「ミックスイン」できるタイプを作成し、そのタイプにいくつかの有益な機能を提供することです。

繰り返しますが、すでに実装されているインターフェースについて考えてみてください。

私はミックスインを主にサポートしていない言語で開発しているため、個人的にはミックスインを使用していません。あなたのための瞬間。しかし、もう一度やり直します。私は工夫された例を使用します-ほとんどの言語はすでに何らかの方法で機能を提供しています-しかし、うまくいけば、ミックスインがどのように作成され使用されるかを説明します。ここに行く:

XMLとの間でシリアル化できる型があるとします。タイプには、タイプのデータ値を含むXMLフラグメントを含む文字列を返す「ToXML」メソッドと、タイプが文字列のXMLフラグメントからデータ値を再構築できる「FromXML」を提供する必要があります。繰り返しになりますが、これは不自然な例なので、おそらくファイルストリームを使用するか、言語のランタイムライブラリのXML Writerクラスを使用します。ポイントは、オブジェクトをXMLにシリアル化し、XMLから新しいオブジェクトを取得することです。

この例のもう1つの重要な点は、これを一般的な方法で実行することです。シリアル化するすべての型に対して "ToXML"および "FromXML"メソッドを実装する必要はありません。型がこれを実行して機能することを確認する一般的な方法が必要です。コードを再利用したい。

言語でサポートされている場合は、XmlSerializableミックスインを作成して作業を行うことができます。このタイプは、ToXMLおよびFromXMLメソッドを実装します。この例では重要ではないメカニズムを使用して、ToXMLによって返されるXMLフラグメントを構築するために混合される任意のタイプから必要なすべてのデータを収集でき、FromXMLがそのときにデータを復元することも同様に可能です。呼ばれた。

以上です。これを使用するには、XmlSerializableから継承してXMLにシリアル化する必要がある任意の型を使用します。その型をシリアル化または逆シリアル化する必要があるときはいつでも、ToXMLまたはFromXMLを呼び出すだけです。実際、XmlSerializableは完全な型であり、ポリモーフィックなので、XmlSerializable型の配列のみを受け入れて、元の型について何も知らないドキュメントシリアライザーを構築することができます。

このシナリオを他の目的で使用することを想像してみてください。ミックスインを作成するすべてのクラスがすべてのメソッド呼び出しをログに記録することを保証するミックスインを作成したり、ミックスインするタイプにトランザクション性を提供するミックスインを作成したりします。

タイプに影響を与えずにタイプに少量の機能を追加するように設計された小さな基本タイプとしてミックスインを考えるだけなら、あなたは黄金です。

うまくいけば。:)


25
ねえ、あなたは「多形共鳴」というフレーズが好きですか?自分で作りました。おもう。多分私はどこかの物理学でそれを聞いた...
ランドルフォ

50
私はあなたの最初の文に少し同意しません。Rubyは単一継承言語であり、ミックスインは別のクラスから継承せずに特定のクラスにメソッドを追加する方法です。
ケルティア

23
@ケルティア:ミックスインは、定義上、多重継承だと思います。Rubyの場合、それらは適切なミックスインではなく、モンキーパッチ(または何か他のもの)です。Rubyの人々はそれをミックスインと呼ぶかもしれませんが、それは別の種類のものです。
S.Lott、2009

10
実際、真のミックスインは多重継承を使用できません。ミックスインには、継承せずに、あるクラスのメソッドや属性などが含まれます。これは、コードの再利用の利点を多態性に見せる傾向がありますが、親子関係を決定する問題(死のダイヤなど)は除外します。Mixinをサポートする言語は、Mixinクラスを部分的に含めることもできます(物事は少し似ているように聞こえ始めます)アスペクト)。
Trevor

8
記録のために、Javaはデフォルトのメソッドでミックスインをサポートするようになりました。
shmosel

170

この回答は、次の例を使用してミックスインを説明することを目的としています。

  • 自己完結型:短く、例を理解するためにライブラリを知る必要はありません。

  • Pythonでは、他の言語ではありません。

    Rubyなどの他の言語の例があったことは理解できますが、これらの言語では用語がはるかに一般的であるためですが、これはPythonスレッドです。

それは論争の的となる質問も考慮しなければならない:

ミックスインを特徴付けるために多重継承が必要ですか?

定義

Pythonのミックスインとは何かを明確に述べている「権威ある」情報源からの引用はまだ見ていません。

私はミックスインの2つの可能な定義を見ました(それらが抽象的な基本クラスのような他の同様の概念と異なると見なされる場合)、そして人々はどちらが正しいかについて完全に同意しません。

コンセンサスは言語によって異なる場合があります。

定義1:多重継承なし

ミックスインは、クラスの一部のメソッドがクラスで定義されていないメソッドを使用するようなクラスです。

したがって、クラスはインスタンス化されることを意図しておらず、基本クラスとして機能します。それ以外の場合、インスタンスには、例外を発生させずに呼び出すことができないメソッドがあります。

一部のソースが追加する制約は、クラスにはデータのみが含まれ、メソッドのみが含まれる可能性があることですが、これが必要な理由はわかりません。ただし、実際には、多くの便利なミックスインにはデータがなく、データのない基本クラスの方が使いやすくなっています。

古典的な例は、<=とからのすべての比較演算子の実装です==

class ComparableMixin(object):
    """This class has methods which use `<=` and `==`,
    but this class does NOT implement those methods."""
    def __ne__(self, other):
        return not (self == other)
    def __lt__(self, other):
        return self <= other and (self != other)
    def __gt__(self, other):
        return not self <= other
    def __ge__(self, other):
        return self == other or self > other

class Integer(ComparableMixin):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i

assert Integer(0) <  Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) >  Integer(0)
assert Integer(1) >= Integer(1)

# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o 

この特定の例は、functools.total_ordering()デコレータを介して実現できたかもしれませんが、ここでのゲームはホイールを再発明することでした:

import functools

@functools.total_ordering
class Integer(object):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i

assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)

定義2:多重継承

ミックスインは、基本クラスの一部のメソッドが定義していないメソッドを使用する設計パターンであり、そのメソッドは、定義1のような派生クラスではなく、別の基本クラスによって実装されることを意図しています。

ミックスインクラスという用語は、そのデザインパターンで使用することを目的とする基本クラスを指します(メソッドを使用するものか、それを実装するものか?)

特定のクラスがミックスインであるかどうかを判断するのは簡単ではありません。メソッドを派生クラスに実装するだけの場合もあります。その場合は、定義1に戻ります。作成者の意図を考慮する必要があります。

このパターンは興味深いもので、基本クラスのさまざまな選択で機能を再結合することができるためです。

class HasMethod1(object):
    def method(self):
        return 1

class HasMethod2(object):
    def method(self):
        return 2

class UsesMethod10(object):
    def usesMethod(self):
        return self.method() + 10

class UsesMethod20(object):
    def usesMethod(self):
        return self.method() + 20

class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass

assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22

# Nothing prevents implementing the method
# on the base class like in Definition 1:

class C3_10(UsesMethod10):
    def method(self):
        return 3

assert C3_10().usesMethod() == 13

信頼できるPythonの出現

collections.abc公式ドキュメントでは、ドキュメントでMixinメソッドという用語を明示的に使用しています。

それはクラスの場合、

  • 実装する __next__
  • 単一のクラスから継承 Iterator

次に、クラスは無料で__iter__ ミックスインメソッドを取得します。

したがって、少なくともドキュメントのこの時点では、mixinは多重継承を必要とせず、定義1と一貫しています。

もちろん、ドキュメントは異なる点で矛盾する可能性があり、他の重要なPythonライブラリは、ドキュメントの他の定義を使用している可能性があります。

このページでは、という用語も使用しています。これSet mixinは、クラスがMixinクラスのようでSetあり、IteratorMixinクラスと呼ぶことができることを明確に示唆しています。

他の言語で

  • Ruby:プログラミングRubyやRubyプログラミング言語などの主要な参考書で述べられているように、ミックスインに多重継承を必要としないことは明らかです。

  • C ++:実装されていないメソッドは、純粋な仮想メソッドです。

    定義1は、抽象クラス(純粋な仮想メソッドを持つクラス)の定義と一致します。そのクラスはインスタンス化できません。

    定義2は仮想継承で可能です。2つの派生クラスからの多重継承


37

私はそれらを多重継承を使用する統制のとれた方法と考えています-最終的にミックスインは、ミックスインと呼ばれるクラスに関する規則に従う(おそらく)もう1つのpythonクラスだからです。

Mixinと呼ぶものを管理する規則についての私の理解は、Mixinです。

  • メソッドを追加しますがインスタンス変数は追加しません(クラス定数は問題ありません)
  • object(Python)からのみ継承

そうすることで、多重継承の潜在的な複雑さを制限し、(完全多重継承と比較して)どこを見なければならないかを制限することで、プログラムのフローを追跡することを合理的に簡単にします。これらはrubyモジュールに似ています

インスタンス変数を追加したい場合(単一継承で許可されているよりも柔軟性がある場合)は、合成を行う傾向があります。

そうは言っても、インスタンス変数を持つXYZMixinと呼ばれるクラスを見てきました。


30

ミックスインは、クラスが機能を提供するプログラミングの概念ですが、インスタンス化に使用することを意図していません。ミックスインの主な目的は、スタンドアロンの機能を提供することであり、ミックスイン自体が他のミックスインとの継承を持たず、状態を回避することが最善です。Rubyなどの言語では、いくつかの直接的な言語サポートがありますが、Pythonではサポートされていません。ただし、マルチクラス継承を使用して、Pythonで提供される機能を実行できます。

私はこのビデオhttp://www.youtube.com/watch?v=v_uKI2NOLEMを見て、ミックスインの基本を理解しました。初心者にとって、ミックスインの基本と、それらがどのように機能するか、およびそれらを実装する際に直面する可能性のある問題を理解することは、非常に役立ちます。

ウィキペディアは今でも最高です:http : //en.wikipedia.org/wiki/Mixin


29

ミックスインと多重継承を区別するものは何ですか?それは単なる意味論の問題ですか?

ミックスインは多重継承の限定された形式です。一部の言語では、クラスにミックスインを追加するメカニズムが(構文の点で)継承のメカニズムとは少し異なります。

特にPythonのコンテキストでは、ミックスインはサブクラスに機能を提供する親クラスですが、それ自体をインスタンス化することは意図されていません。

「それは単なる多重継承であり、実際にはミックスインではない」と言われるのは、ミックスインと混同される可能性のあるクラスが実際にインスタンス化されて使用される可能性がある場合です。

多重継承の例

このドキュメントの例は、OrderedCounterです。

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

モジュールのCounterとの両方をサブクラス化OrderedDictcollectionsます。

CounterOrderedDictはどちらも、インスタンス化して自分で使用することを目的としています。ただし、両方をサブクラス化することで、順序付けされたカウンターを作成し、各オブジェクトのコードを再利用できます。

これはコードを再利用する強力な方法ですが、問題が発生する可能性もあります。オブジェクトの1つにバグがあることが判明した場合、注意せずに修正すると、サブクラスにバグが発生する可能性があります。

ミックスインの例

ミックスインは通常、OrderedCounterのような協調的な多重継承が持つ可能性のある潜在的なカップリングの問題なしにコードを再利用する方法として宣伝されています。ミックスインを使用するときは、データと密接に結びついていない機能を使用します。

上記の例とは異なり、ミックスインはそれ自体で使用するためのものではありません。新しい機能または異なる機能を提供します。

たとえば、標準ライブラリには、ライブラリにいくつかのミックスインがありsocketserverます

各タイプのサーバーのフォークバージョンとスレッドバージョンは、これらのミックスインクラスを使用して作成できます。たとえば、ThreadingUDPServerは次のように作成されます。

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

UDPServerで定義されたメソッドをオーバーライドするため、ミックスインクラスが最初になります。さまざまな属性を設定すると、基になるサーバーメカニズムの動作も変更されます。

この場合、mixinメソッドはUDPServerオブジェクト定義のメソッドをオーバーライドして、同時実行性を可能にします。

オーバーライドされたメソッドはのようでprocess_requestあり、別のメソッドも提供しますprocess_request_thread。ここではソースコードからです

class ThreadingMixIn:
        """Mix-in class to handle each request in a new thread."""

        # Decides how threads will act upon termination of the
        # main process
        daemon_threads = False

        def process_request_thread(self, request, client_address):
            """Same as in BaseServer but as a thread.
            In addition, exception handling is done here.
            """
            try:
                self.finish_request(request, client_address)
            except Exception:
                self.handle_error(request, client_address)
            finally:
                self.shutdown_request(request)

        def process_request(self, request, client_address):
            """Start a new thread to process the request."""
            t = threading.Thread(target = self.process_request_thread,
                                 args = (request, client_address))
            t.daemon = self.daemon_threads
            t.start()

考案された例

これは主にデモ目的のミックスインです-ほとんどのオブジェクトはこのreprの有用性を超えて進化します:

class SimpleInitReprMixin(object):
    """mixin, don't instantiate - useful for classes instantiable
    by keyword arguments to their __init__ method.
    """
    __slots__ = () # allow subclasses to use __slots__ to prevent __dict__
    def __repr__(self):
        kwarg_strings = []
        d = getattr(self, '__dict__', None)
        if d is not None:
            for k, v in d.items():
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        slots = getattr(self, '__slots__', None)
        if slots is not None:
            for k in slots:
                v = getattr(self, k, None)
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        return '{name}({kwargs})'.format(
          name=type(self).__name__,
          kwargs=', '.join(kwarg_strings)
          )

使用法は次のとおりです。

class Foo(SimpleInitReprMixin): # add other mixins and/or extend another class here
    __slots__ = 'foo',
    def __init__(self, foo=None):
        self.foo = foo
        super(Foo, self).__init__()

そして使い方:

>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)

11

ここには良い説明がいくつかあると思いますが、別の見方をしたいと思います。

Scalaでは、ここで説明したようにミックスインを実行できますが、非常に興味深いのは、実際にミックスインが「融合」して、継承する新しい種類のクラスを作成することです。基本的に、複数のクラス/ミックスインから継承するのではなく、ミックスインのすべてのプロパティを継承する新しい種類のクラスを生成します。Scalaは多重継承が現在サポートされていないJVM(Java 8以降)に基づいているため、これは理にかなっています。ちなみに、このミックスインクラス型は、Scalaの特性と呼ばれる特殊な型です。

これは、クラスの定義方法を示唆しています。クラスNewClassは、FirstMixinをSecondMixinで拡張し、ThirdMixinで拡張しています...

CPythonインタープリターが同じ(mixinクラス構成)を行うかどうかはわかりませんが、驚くことはありません。また、C ++のバックグラウンドから来ているので、ABCや「インターフェース」をミックスインと同等のものとは呼びません。これは同様の概念ですが、使用方法と実装方法は異なります。


9

それ以上の方法が他にない場合(継承の代わりに合成、または独自のクラスにモンキーパッチを適用する方法など)を見つけることができる場合は、新しいPythonコードにミックスインしないことをお勧めします努力。

古いスタイルのクラスでは、別のクラスからいくつかのメソッドを取得する方法としてミックスインを使用できました。しかし、新しいスタイルの世界では、ミックスインでさえ、すべてがから継承されobjectます。つまり、多重継承を使用すると、当然MROの問題が発生します

Pythonで多重継承MROを機能させる方法はありますが、最も重要なのはsuper()関数ですが、super()を使用してクラス階層全体を実行する必要があり、制御のフローを理解するのがかなり困難です。


3
バージョン2.3以降、PythonはPython 2.3メソッド解決順序またはメソッド解決順序で説明されている「C3メソッド解決」を使用します。
webwurst 2012年

11
個人的には、ほとんどの場合、サルパッチングよりもミックスインを採用します。コードを推論し、コードをたどるのは簡単です。
tdammers 2013

5
反対投票。あなたの答えは開発スタイルについての妥当な意見を表していますが、実際の質問に実際に取り組むことはしません。
ライアンB.リンチ

8

おそらくいくつかの例が役立ちます。

クラスを構築していて、それを辞書のように動作させたい場合は、__ __必要なさまざまなメソッドをすべて定義できます。しかし、それは少し苦痛です。別の方法として、いくつかを定義し、(他の継承に加えて)継承する(py3kにUserDict.DictMixin移動)ことcollections.DictMixinができます。これは、辞書APIの残りすべてを自動的に定義する効果があります。

2番目の例:GUIツールキットwxPythonを使用すると、複数の列を持つリストコントロールを作成できます(たとえば、Windowsエクスプローラーのファイル表示など)。デフォルトでは、これらのリストはかなり基本的です。ListCtrlから継承して適切なミックスインを追加することで、列ヘッダーをクリックして特定の列でリストを並べ替える機能など、追加の機能を追加できます。


8

これはPythonの例ではありませんが、Dプログラミング言語では、この用語mixinはほとんど同じ方法で使用される構造を指すために使用されます。ものの山をクラスに追加します。

Dでは(これはMIを実行しません)、これはテンプレートを構文的に認識し、安全なマクロであると考えて、スコープに挿入します。これにより、クラス、構造体、関数、モジュールなどの1行のコードを任意の数の宣言に展開できます。


2
ミックスインは、D、Rubyなどで使用される一般的な用語です。Wikipediaによると、それらは古い学校のlispシステムに由来し、1983年に初めて文書化されました。 en.wikipedia.org/wiki/...
リーB

7

OPはC ++でのミックスインについて聞いたことがないと述べました。おそらくC ++ではCuriously Recurring Template Pattern(CRTP)と呼ばれているためです。また、@ Ciro Santilliは、ミックスインはC ++の抽象基本クラスを介して実装されると述べました。抽象基本クラスはミックスインの実装に使用できますが、実行時の仮想関数の機能は、実行時の仮想テーブル検索のオーバーヘッドなしに、コンパイル時にテンプレートを使用して実現できるため、やり過ぎです。

CRTPパターンについて詳しくは、こちらをご覧ください

以下のテンプレートクラスを使用して、@ Ciro Santilliの回答のpythonの例をC ++に変換しました。

    #include <iostream>
    #include <assert.h>

    template <class T>
    class ComparableMixin {
    public:
        bool operator !=(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) == static_cast<T&>(other));
        }
        bool operator <(ComparableMixin &other) {
            return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
        }
        bool operator >(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
        }
        bool operator >=(ComparableMixin &other) {
            return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
        }
        protected:
            ComparableMixin() {}
    };

    class Integer: public ComparableMixin<Integer> {
    public:
     Integer(int i) {
         this->i = i;
     }
     int i;
     bool operator <=(Integer &other) {
         return (this->i <= other.i);
     }
     bool operator ==(Integer &other) {
         return (this->i == other.i);
     }
    };

int main() {

    Integer i(0) ;
    Integer j(1) ;
    //ComparableMixin<Integer> c; // this will cause compilation error because constructor is protected.
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);

    return 0;
}

編集:ComparableMixinに保護されたコンストラクターを追加して、継承のみが可能でインスタンス化できないようにしました。例を更新して、保護されたコンストラクターがComparableMixinのオブジェクトの作成時にコンパイルエラーを引き起こす方法を示しました。


ミックスインとCRTPは、C ++ではまったく同じものではありません。
アシュラムン

6

おそらくルビーの例が役立つでしょう:

ミックスインComparableを含めて1つの関数を定義できます。ミックス"<=>(other)"インはこれらのすべての関数を提供します。

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

これは、 <=>(other)、正しい結果をて返すことによって行われます。

"instance <=> other"リターン0の両方のオブジェクトが0よりも小さい、等しい場合場合instanceよりも大きいotherと0より大きい場合はother大きいです。


これは、Pythonに同様のミックスインを提供する投稿です。提案はの__lt__代わりにベースとして定義していますが、__cmp__後者は実際には非推奨であり、使用することはお勧めしません。私にとって非常に複雑なのではなく、そのミックスインを使用する方が簡単そうですデコレータ(の一部functoolsが- )この1つは上でよりダイナミックに反応することができるかもしれ ...比較が提供されている
トビアスKienzler

6

mixinは、クラスに機能を追加する方法を提供します。つまり、必要なクラス内にモジュールを含めることにより、モジュールで定義されたメソッドを操作できます。ルビーは多重継承をサポートしていませんが、それを実現するための代替手段としてミックスインを提供しています。

以下は、mixinを使用して多重継承を実現する方法を説明する例です。

module A    # you create a module
    def a1  # lets have a method 'a1' in it
    end
    def a2  # Another method 'a2'
    end
end

module B    # let's say we have another module
    def b1  # A method 'b1'
    end
    def b2  #another method b2
    end
end

class Sample    # we create a class 'Sample'
    include A   # including module 'A' in the class 'Sample' (mixin)
    include B   # including module B as well

    def S1      #class 'Sample' contains a method 's1'
    end
end

samp = Sample.new    # creating an instance object 'samp'

# we can access methods from module A and B in our class(power of mixin)

samp.a1     # accessing method 'a1' from module A
samp.a2     # accessing method 'a2' from module A
samp.b1     # accessing method 'b1' from module B
samp.b2     # accessing method 'a2' from module B
samp.s1     # accessing method 's1' inside the class Sample

4
これと一般的な多重継承の違いは何ですか?
Ciro Santilli冠状病毒审查六四事件法轮功

違いは、モジュールからインスタンスを作成できないことですが、一般的なクラスとモジュールの間に区別がない場合、ミックスインは明示的なものではなく、一般的なクラスがどこにあり、ミックスインがどこにあるかを理解するのは難しい
ka8725

Rubyのミックスインはインスタンス化できないクラスですが、多重継承に使用する必要がありますか?
Trilarion 2014

6

私はPythonミックスインを使用して、Python milterの単体テストを実装しました。通常、milterはMTAと通信するため、単体テストは困難です。テストミックスインは、MTAと通信するメソッドをオーバーライドし、代わりにテストケースによって駆動されるシミュレーション環境を作成します。

したがって、次のように、spfmilterなどの変更されていないmilterアプリケーションと、mixin TestBaseを使用します。

class TestMilter(TestBase,spfmilter.spfMilter):
  def __init__(self):
    TestBase.__init__(self)
    spfmilter.config = spfmilter.Config()
    spfmilter.config.access_file = 'test/access.db'
    spfmilter.spfMilter.__init__(self)

次に、milterアプリケーションのテストケースでTestMilterを使用します。

def testPass(self):
  milter = TestMilter()
  rc = milter.connect('mail.example.com',ip='192.0.2.1')
  self.assertEqual(rc,Milter.CONTINUE)
  rc = milter.feedMsg('test1',sender='good@example.com')
  self.assertEqual(rc,Milter.CONTINUE)
  milter.close()

http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup


4

以前の応答はMixInが何であるかを非常によく定義していると思います。しかし、それらをよりよく理解するためには、比較することが有用であるかもしれないミックスインをして抽象クラスインタフェースコード/実装の観点から:

1.抽象クラス

  • 1つ以上の抽象メソッドを含める必要があるクラス

  • 抽象クラスに 、状態(インスタンス変数)と非抽象メソッド含めることができます

2.インターフェース

  • インターフェースには抽象メソッドのみが含まれます(非抽象メソッドおよび内部状態は含まれません)

3. MixIns

  • MixIns(インターフェイスなど)に内部状態(インスタンス変数)が含まれていません
  • MixInには、1つ以上の非抽象メソッド含まれます(インターフェースとは異なり、非抽象メソッドを含めることができます)

たとえばPythonでは、上記のすべてがclasses として定義されているため、これらは単なる規則です。しかし、両方の共通の特徴抽象クラス、インタフェースおよびミックスインは、彼らがいることであるべきではない、自分の上に存在する、すなわちインスタンス化すべきではありません。


3

私はあなたがc#のバックグラウンドを持っていると読んだ。したがって、良い出発点は.NETのmixin実装かもしれません。

あなたはhttp://remix.codeplex.com/で codeplexプロジェクトをチェックアウトしたいかもしれません

概要については、lang.netシンポジウムリンクをご覧ください。codeplexページのドキュメントにはまだまだあります。

ステファンよろしく

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.