私は自分のコードでZopeインターフェースを使い始めましたが、今のところ、それらは実際には単なるドキュメントです。私はそれらを使用して、クラスが持つべき属性を指定し、それらを適切なクラスに明示的に実装し、期待する場所で明示的にチェックします。これは問題ありませんが、クラスがインターフェイスを実装していると言ったことを確認するだけでなく、クラスがインターフェイスを実装していることを実際に確認するなど、可能であればもっと多くのことをしてもらいたいと思います。私はzopewikiを数回読んだことがありますが、それでも私が現在行っていることよりもはるかに多くのインターフェースの使用法を見ることができません。ですから、私の質問は、これらのインターフェースを他に何に使用できるのか、そしてそれらをどのように使用するのかということです。
オブジェクトまたはクラスがインターフェースを実装しているかどうかを実際にテストできます。そのためには、verify
モジュールを使用できます(通常はテストで使用します)。
>>> from zope.interface import Interface, Attribute, implements
>>> class IFoo(Interface):
... x = Attribute("The X attribute")
... y = Attribute("The Y attribute")
>>> class Foo(object):
... implements(IFoo)
... x = 1
... def __init__(self):
... self.y = 2
>>> from zope.interface.verify import verifyObject
>>> verifyObject(IFoo, Foo())
True
>>> from zope.interface.verify import verifyClass
>>> verifyClass(IFoo, Foo)
True
インターフェイスは、不変条件の設定とテストにも使用できます。あなたはここでより多くの情報を見つけることができます:
私が働いているところでは、ZCA、またはInterface
sを使用してスワップ可能およびプラグ可能なコンポーネントを作成するためのフレームワーク全体である Zope Component Architecture を使用できるようにインターフェイスを使用します。 ZCAを使用することで、ソフトウェアをフォークしたり、クライアントごとの多くのビットをすべてメインツリーで混乱させたりすることなく、あらゆる種類のクライアントごとのカスタマイズに対応できます。残念ながら、Zopewikiはかなり不完全なことがよくあります。その ZCAのpypiページ にZCAの機能のほとんどの良いが簡潔な説明があります。
クラスが特定のInterface
のすべてのメソッドを実装していることを確認するなどの目的でInterface
sを使用することはありません。理論的には、これは、インターフェイスに別のメソッドを追加するときに、インターフェイスを実装するすべてのクラスに新しいメソッドを追加することを覚えているかどうかを確認するのに役立つ場合があります。個人的には、古いものを変更するよりも、新しいInterface
を作成することを強く好みます。古いInterfaces
を変更することは、pypiまたは組織の他の部分にリリースされた卵に含まれると、通常は非常に悪い考えです。
用語に関する簡単なメモ:クラス実装Interface
s、およびオブジェクト(クラスのインスタンス)provideInterface
s。 Interface
を確認する場合は、ISomething.implementedBy(SomeClass)
またはISomething.providedBy(some_object)
と記述します。
したがって、ZCAが役立つ場所の例に至るまで。 ZCAを使用してブログをモジュール化して、ブログを書いているとしましょう。投稿ごとにBlogPost
オブジェクトがあり、これはIBlogPost
インターフェイスを提供します。これらはすべて、便利な_my.blog
_ Eggで定義されています。また、ブログの構成をBlogConfiguration
を提供するIBlogConfiguration
オブジェクトに保存します。これを出発点として使用すると、必ずしも_my.blog
_に触れることなく、新しい機能を実装できます。
以下は、ベース_my.blog
_ Eggを変更せずにZCAを使用して実行できることの例のリストです。当時はブログを実装していませんでしたが、私または私の同僚は、実際のクライアント向けプロジェクトでこれらすべてのことを実行しました(そしてそれらが有用であることがわかりました)。 :)ここでのユースケースのいくつかは、CSSファイルの印刷などの他の手段によってよりよく解決される可能性があります。
BrowserView
を提供するすべてのオブジェクトに追加のビュー(IBlogPost
s、通常は [〜#〜] zcml [〜#〜] に_browser:page
_ディレクティブで登録)を追加します。 _my.blog.printable
_の卵を作ることができました。そのEggはprint
のIBlogPost
と呼ばれるBrowserViewを登録します。これは、うまく印刷されるHTMLを生成するように設計された Zope Page Template を介してブログ投稿をレンダリングします。そのBrowserView
はURL _/path/to/blogpost/@@print
_に表示されます。
Zopeのイベントサブスクリプションメカニズム。 RSSフィードを公開したいが、要求に応じてではなく事前に生成したいとします。 _my.blog.rss
_エッグを作成できます。そのEggで、IBlogPost
を提供するオブジェクトで、 IObjectModified (_zope.lifecycleevent.interfaces.IObjectModified
_)を提供するイベントのサブスクライバーを登録します。そのサブスクライバーは、IBlogPost
を提供するものの属性が変更されるたびに呼び出され、ブログ投稿が表示されるすべてのRSSフィードを更新するために使用できます。
この場合、ブログ投稿を変更する各IBlogPostModified
sの最後に送信されるBrowserView
イベントがある方がよい場合があります。これは、IObjectModified
が属性の変更ごとに1回送信されるためです。これは、パフォーマンスのために頻繁に行われる可能性があります。
アダプター。アダプターは、あるインターフェースから別のインターフェースに効果的に「キャスト」されます。プログラミング言語オタクの場合:Zopeアダプターは、Python(「open」とは「任意のEggからさらにケースを追加できる」という意味)で「open」多重ディスパッチを実装し、より具体的なインターフェースを一致させますあまり具体的でない一致よりも優先されます(Interface
クラスは相互のサブクラスになる可能性があり、これはまさにあなたが望むことを実行します。)
1つのInterface
からのアダプターは、非常に優れた構文ISomething(object_to_adapt)
で呼び出すか、関数_zope.component.getAdapter
_を介して検索できます。複数のInterface
sからのアダプターは、関数_zope.component.getMultiAdapter
_を介して検索する必要がありますが、これは少しきれいではありません。
Interface
sの特定のセットに対して、アダプターの登録時に指定する文字列name
によって区別される、複数のアダプターを持つことができます。名前のデフォルトは_""
_です。たとえば、BrowserView
sは、実際には、それらが登録されているインターフェースとHTTPRequestクラスが実装するインターフェースから適応するアダプターです。 zope.component.getAdapters( (IAdaptFrom,), IAdaptTo )
を使用して、Interface
sの1つのシーケンスから別のInterface
に登録されているアダプターのすべてallを検索することもできます。 (名前、アダプター)ペアのシーケンス。これは、プラグインが接続するためのフックを提供するための非常に優れた方法として使用できます。
ブログのすべての投稿と構成を1つの大きなXMLファイルとして保存したいとします。 IXMLSegment
を定義する_my.blog.xmldump
_ Eggを作成し、アダプターをIBlogPost
からIXMLSegment
に、アダプターをIBlogConfiguration
からIXMLSegment
に登録します。 IXMLSegment(object_to_serialize)
と書くことで、シリアル化するオブジェクトに適したアダプターを呼び出すことができます。
_my.blog.xmldump
_以外の卵からIXMLSegment
に、他のさまざまなものからさらにアダプターを追加することもできます。 ZCMLには、Eggがインストールされている場合にのみ、特定のディレクティブを実行できる機能があります。これを使用して、_my.blog.rss
_を_my.blog.xmldump
_に依存させることなく、_my.blog.rss
_がたまたまインストールされた場合にIRSSFeed
からIXMLSegment
へのアダプターを_my.blog.xmldump
_に登録させることができます。
Viewlet
sは、ページ内の特定の場所に「サブスクライブ」させることができる小さなBrowserView
sのようなものです。今のところすべての詳細を思い出せませんが、これらはサイドバーに表示したいプラグインのようなものに非常に適しています。
彼らがベースのZopeの一部なのかPloneの一部なのか、私はすぐに思い出せません。 Ploneは大きくて複雑なソフトウェアであり、少し遅い傾向があるため、解決しようとしている問題が実際に実際のCMSを必要としない限り、Ploneの使用はお勧めしません。
Viewlet
sは、TAL式で 'object/@@ some_browser_view'を使用するか、queryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )
を使用して相互に呼び出すことができるため、実際には必ずしもBrowserView
sは必要ありませんが、それでもかなり優れています。
マーカーInterface
s。マーカーInterface
は、メソッドも属性も提供しないInterface
です。 _ISomething.alsoProvidedBy
_を使用して、実行時に任意のオブジェクトにマーカーInterface
を追加できます。これにより、たとえば、特定のオブジェクトで使用されるアダプタと、そのオブジェクトで定義されるBrowserView
sを変更できます。
これらの各例をすぐに実装するのに十分な詳細を説明していないことをお詫びしますが、それぞれ約ブログ投稿が必要です。
Zopeインターフェースは、相互に依存してはならない2つのコードを分離するための便利な方法を提供します。
モジュールa.pyで挨拶を印刷する方法を知っているコンポーネントがあるとします。
>>> class Greeter(object):
... def greet(self):
... print 'Hello'
そして、モジュールb.pyで挨拶を出力する必要があるいくつかのコード:
>>> Greeter().greet()
'Hello'
この配置では、b.py(別のパッケージで配布される場合があります)に触れずに挨拶を処理するコードを交換するのが困難になります。代わりに、IGreeterインターフェイスを定義する3番目のモジュールc.pyを導入できます。
>>> from zope.interface import Interface
>>> class IGreeter(Interface):
... def greet():
... """ Gives a greeting. """
これを使用して、a.pyとb.pyを分離できます。グリータークラスをインスタンス化する代わりに、b.pyはIGreeterインターフェースを提供するユーティリティを要求するようになりました。そしてa.pyは、Greeterクラスがそのインターフェースを実装することを宣言します。
(a.py)
>>> from zope.interface import implementer
>>> from zope.component import provideUtility
>>> from c import IGreeter
>>> @implementer(IGreeter)
... class Greeter(object):
... def greet(self):
... print 'Hello'
>>> provideUtility(Greeter(), IGreeter)
(b.py)
>>> from zope.component import getUtility
>>> from c import IGreeter
>>> greeter = getUtility(IGreeter)
>>> greeter.greet()
'Hello'
私はZopeインターフェースを使用したことがありませんが、 metaclass を作成することを検討してください。これは、初期化時にクラスのメンバーをインターフェースと照合し、メソッドが実装されていない場合はランタイム例外を発生させます。
Pythonを使用すると、他のオプションはありません。コードを検査する「コンパイル」ステップを使用するか、実行時に動的に検査します。