この記事を読むのに約2分かかります。
ソフトウェア業界では、唯一の定数は変化です。製品マネージャーが変更され、製品要件が変更され、コードも変更されます。コードの設計と変更が異なれば、ワークロードも異なります。変更によっては、ほとんどリファクタリングが必要なものもあれば、構成ファイルを変更するか、クラスにコード行を追加するだけでよいものもあります。もちろん、優れたコード設計は、優れたスケーラビリティ、高い凝集性、および低い結合を備えているため、保守が容易です。優れたコードデザインが必要な場合は、デザインパターンを学ぶ必要があります。今日は、Pythonのインターフェースに基づいてプログラミングする方法を紹介します。
1994 2015年のGoFの「DesignPatterns」ブックには、実装プログラミングではなくインターフェイスに基づく重要な原則があります。元の英語のテキストは「実装ではなくインターフェイスへのプログラム」です。ここで説明するインターフェイスは特定のプログラミング言語ではありません。言語に依存しないのインターフェイスは、開発者がユーザーに提供する機能のリストを参照します。これを理解することは非常に重要です。インターフェイスは、Java言語のキーワードinterfaceによって実装されます。Javaはクラスの複数の継承をサポートしていませんが、インターフェイスの複数の継承をサポートしています。Java開発者はインターフェイスに精通しています。PythonはJava設計をまったく必要としませんが、インターフェイスの利点から学ぶことができます。
たとえば、画像のアップロード機能を実装していて、現在QiniuCloudをストレージに使用しているとします。クラスは次のようになります。
classQnyImageStore(object):
def getToken():
pass
def upload_qny(self,image):print("Qny upload.")
# do something
def download_qny(self,image):print("Qny download.")
# do something
実際の開発では、多くのコード行と3つ以上の関数があり、数百または数千の場所で呼び出され、数百のファイルに散在しています。しばらくして、同社は独自のプライベートクラウドを構築し、Qiniu Cloudを使用できなくなり、独自の[Cloud Storage](https://cloud.tencent.com/product/cos?from=10680)に変更する必要があるため、クラスを書き直す必要があります。
classOwnImageStore(object):
def upload_own(self,image):print("Qny upload.")
# do something
def download_own(self,image):print("Qny download.")
# do something
次に、Qiniuを使用するすべての場所を置き換え、関数の名前も置き換える必要があります。最後に、人生のどの部分も考慮していない場所で複数回テストする必要があり、エラーが発生します。ついに変更されました。ある日突然、需要が再び変化しました。クラウドサービスに問題が発生することが多かったため、AlibabaCloudに切り替える必要がありました。前回の辛いトスの後、今度は変わるのを見て、直接血を吐きました。
実際、問題は、作成するコードが十分に一般的でなく、名前が十分に抽象的でないことです。クラスの関数名がアップロードとダウンロードを使用している場合、変更するコードの量が半分に減る可能性があります。クラス名を置き換えるだけです。実際、インターフェイスを使用してコードの変更量を減らすことができます。インターフェイスと実装を分離することで、不安定な実装をカプセル化し、安定したインターフェイスを公開します。アップストリームシステムとダウンストリームシステムが当社が開発した関数を使用する場合、インターフェイスで宣言された関数リストを使用するだけでよいため、実装が変更された場合でも、カップリングを減らしてスケーラビリティを向上させるために、アップストリームシステムのコードを基本的に変更する必要はありません。 。以下に、この問題に関するインターフェイスベースのコード実装方法を示します。
from abc import ABCMeta, abstractmethod
classImageStore(metaclass = ABCMeta):
@ abstractmethod
def upload(self,image):
pass
# raise NotImplementedError
@ abstractmethod
def download(self,image):
pass
# raise NotImplementedError
インターフェイスを定義した後、インターフェイスを継承するクラスは、正しく使用するためにアップロードメソッドとダウンロードメソッドを書き直す必要があります。そうしないと、例外がスローされます。ここでは、インターフェイスで例外をスローする必要はありません。標準ライブラリabcはすでに存在します。これらのタスクを実行しました。
目的は、実際には制約を適用することです。つまり、プログラムの堅牢性を確保するために、コンパイル時にアップロードおよびダウンロードメソッドを実装およびチェックする必要があります。
classOwnImageStore2(ImageStore):
def upload(self,image):print("Own upload.")
# do something
def download(self,image):print("Own download.")
# do something
classQnyImageStore2(ImageStore):
def getToken():
pass
def upload(self,image):print("Qny upload.")
def download(self,image):print("Qny download.")
# do something
次に、タイプに応じて対応するオブジェクトを呼び出すメソッドを自動的に選択できるインターフェイスを定義します。
classUsedStore(object):
def __init__(self, store):if not isinstance(store, ImageStore): raise Exception('Bad interface')
self._store = store
def upload(self):
self._store.upload('image')
def download(self):
self._store.download('image')
最後に、構成ファイルで、使用している特定のインターフェースを指定できます。
# 他のファイルでは、このように呼び出す必要があります
img =QnyImageStore2()
# img =OwnImageStore2()これらを構成ファイルに入れてください。置き換える必要があるのは構成ファイルを更新するだけです。
store =UsedStore(img)
store.upload()
store.download()
このように、後で新しいイメージストレージを追加するには、対応するクラスを追加し、インターフェイスを継承し、構成ファイルを変更するだけで、多くのコード変更作業を減らすことができます。
python標準ライブラリabc、フルネームはAbstract Base Classesで、次の関数を提供します。
基本:
オブジェクト指向プログラミングの分野では、オブジェクトと相互作用する設計パターンは、「呼び出し」と「チェック」という2つの基本的なカテゴリに分類できます。
呼び出しとは、オブジェクトのメソッドを呼び出すことによってオブジェクトと対話することを指します。通常、これは多態性と組み合わされるため、特定のメソッドを呼び出すと、オブジェクトのタイプに応じて異なるコードが実行される場合があります。
検査とは、(オブジェクトのメソッドの外部にある)外部コードがオブジェクトのタイプまたはプロパティを検査し、この情報に基づいてオブジェクトを処理する方法を決定する機能を指します。
どちらの使用モードも同じ汎用目的を果たします。つまり、多様で新しい可能性のあるオブジェクトの処理を統一された方法でサポートできますが、同時に、異なるタイプのオブジェクトごとにカスタマイズされた処理決定を行うことができます。
古典的なOOP理論では、呼び出しが好ましい設計パターンであり、検査は以前のスタイルの手続き型プログラミングの製品と見なされるため、検査は推奨されません。ただし、実際には、このビューは独断的で厳格すぎるため、Pythonなどの言語の動的な性質とは大きく異なる特定の設計の厳格さにつながります。
特に、オブジェクトクラスの作成者が予測できない方法でオブジェクトを処理する必要がある場合がよくあります。そのオブジェクトのすべての可能なユーザーニーズを満たすすべてのオブジェクトメソッドに組み込まれていることが、常に最良のソリューションであるとは限りません。さらに、ルールやパターンマッチング駆動型ロジックなど、オブジェクトに厳密にカプセル化されている従来のOOP動作要件とは対照的な、強力なスケジューリング哲学が数多くあります。
一方、古典的なOOP理論家による検査に対する批判の1つは、形式主義の欠如と検査されたコンテンツの特殊な性質です。 Pythonなどの言語では、オブジェクトのほぼすべての側面を反映し、外部コードを介して直接アクセスできます。オブジェクトが特定のプロトコルに準拠しているかどうかをテストするには、さまざまな方法があります。たとえば、「このオブジェクトは可変シーケンスコンテナですか?」と尋ねると、「list」の基本クラスを検索したり、「、__ getitem__」という名前のメソッドを検索したりできます。ただし、これらのテストは明白に見えるかもしれませんが、一方が偽陰性を生成し、もう一方が偽陽性を生成するため、正しくないことに注意してください。
一般的に合意されている救済策は、テストを標準化し、正式な形式にグループ化することです。これを行うには、継承メカニズムまたはその他の方法で、標準のテスト可能なプロパティのセットを各クラスに関連付けるのが最も簡単です。各テストには一連のPromiseが付属しています。これには、クラスの一般的な動作に関するPromiseと、他の使用可能なクラスメソッドに関するPromiseが含まれています。
PEPは、Abstract Base Class(ABC)と呼ばれる、これらのテストを編成するための特別な戦略を提案します。 ABCは、オブジェクトの特定の機能を外部の検査官に送信するためにオブジェクトの継承ツリーに追加されるPythonクラスです。 isinstance()を使用してテストを完了します。特定のABCが存在する場合は、テストに合格したことを意味します。
さらに、ABCは、このタイプの特徴的な動作を確立するためのメソッドの最小セットを定義します。 ABCタイプに基づいてオブジェクトを区別するコードは、これらのメソッドが常に存在することを信頼できます。これらの各メソッドには、ABCドキュメントで説明されている一般化された抽象的なセマンティック定義が付属しています。これらの標準の意味上の定義は必須ではありませんが、強くお勧めします。
Pythonの他のすべてと同様に、これらの約束は紳士協定の性質のものです。この場合、これは、言語がABCで行われた約束の一部を実装しているにもかかわらず、具体的なクラスの実装者が次を続けます。
上記の説明を読むと、ABCが基本クラスであることが簡単に理解できます。これを継承すると、javaに似たインターフェイスを作成できます。インターフェイスのメソッドは常に存在し、自信を持って使用でき、調査する必要はありません。
PEP3119には、理解できるサンプルコードも用意されています。
from abc import ABCMeta, abstractmethod
classA(metaclass=ABCMeta):
@ abstractmethod
def foo(self): pass
A() # raises TypeError
classB(A):
pass
B() # raises TypeError
classC(A):
def foo(self):print(42)C() # works
それについては話したくありません。ABCを正しく使用できることを願っています。同時に、Pythonを学ぶことを強くお勧めします。公式のPythonドキュメントとPEP提案をご覧ください。これが最も信頼できる説明です。
また、設定モードも非常に重要なプログラミング手法であり、プログラミングの方法であり、基本的なスキルです。基本的なスキルが足りない場合は、戦闘機を目の前に置いた場合の鑑賞方法や味わい方がわかりません。
デザインパターンをマスターして他の人のコードを見ると、ファイタージェットであり、トラクターである黄金の目が見えます。これは、自分の学習と改善にも非常に役立ちます。作成したコードは、より保守しやすく、読みやすくなります。スケーラビリティ、柔軟性。
デザインパターンに興味のある方は、一緒に勉強してみてください。下の写真からデザインパターンを購入したクラスメートは、友達(somenzz)を追加して12元をキャッシュバックし、大きなグループに参加してPythonテクノロジーを交換します。一人で学んだり、友達がいなかったり、無知であったりしないでください。
デザインパターンの美しさ-王鄭
Recommended Posts