動的で弱く型付けされた言語では、デザインパターンとOOPプラクティスに関する考え方がどのように変わりますか?


11

これらの線に沿ってすでにかなり役立つ質問があります(「非OOPデザインパターン?」)が、動的で型付けの弱い言語を始めたばかりの人の移行の観点について、私はもっと興味があります。

つまり、C ++、C#、またはJavaで長年プログラミングしており、GoFデザインパターン、エンタープライズアプリケーションアーキテクチャのファウラーパターンSOLID原則などに沿って多くの知恵を吸収したとしましょう。 m Ruby、Python、JavaScriptなどに手を出し、自分の知識がどのように適用されるのか疑問に思う。おそらく私は多くの場合に直接翻訳を行うことができますが、ほとんど確実にそれは私の新しい設定を十分に活用していないでしょう。アヒルのタイピングだけでも、私のインターフェースベースの考え方の多くが頭に浮かびます。

何が変わりませんか?何が変わりますか?動的言語初心者が知っておくべき、SOLIDや標準パターン(おそらくまったく新しいパターン)などの基本原則はありますか?

回答:


7

何が変わりませんか?何が変わりますか?

パターンは同じです。言語技術が変わります。

SOLIDのような基本原則はありますか、

はい。確かに、それらは引き続き指針となる原則です。何も変わりません。

動的言語初心者が知っておくべき標準パターン(おそらくまったく新しいパターン)

いくつかのものはユニークです。主な影響は、実装手法が変わることです。

パターンは-まあ- パターンです。法律ではありません。サブルーチンではありません。マクロではありません。それは良いアイデアだから繰り返される良いアイデアです。

良いアイデアがスタイルを失ったり、劇的に変化したりすることはありません。

その他の注意。Pythonは「弱い型付け」ではありません。キャスト操作がないため、JavaやC ++よりも強く型付けされています。[はい、オブジェクトに関連付けられたクラスを偽造する方法がありますが、それはうるさい、法的な点を証明することを除いて行われているようなものではありません。]

また。ほとんどのデザインパターンは、ポリモーフィズムを活用するさまざまな方法に基づいています。

状態コマンド、またはメメント を例として見てください。これらには、クラスの階層があり、ポリモーフィックな状態、コマンド、または状態変化の記憶を作成します。Pythonでこれを実行しても、大きな変更はありません。Pythonのポリモーフィズムは共通の祖先ではなく共通のメソッドに依存するため、マイナーな変更には正確なクラス階層の緩和が含まれます。

また、一部のパターンは、レイトバインディングを達成するための単なる試みです。ほとんどのFactory関連のパターンは、アプリケーション内のすべてのC ++モジュールを再コンパイルせずにクラス階層を簡単に変更できるようにする試みです。これは、動的言語の興味深い最適化ではありません。ただし、実装の詳細を隠す手段としてのファクトリには、依然として大きな価値があります。

一部のパターンは、コンパイラーとリンカーを駆動する試みです。 たとえば、Singletonは、混乱を招くグローバルを作成するために存在しますが、少なくともそれらをカプセル化します。Pythonシングルトンクラスは、好ましい見通しではありません。しかし、Pythonモジュールはすでにシングルトンであるため、私たちの多くはモジュールを使用するだけで、シングルトンクラスを台無しにしないようにしています。


SOLIDで「何も変わらない」とは言いません。言語とそのオブジェクトモデルによっては、Open-Closed PrincipleとLiskov Substitution Principleの両方が無意味になる場合があります。(JavaScriptとGoの両方が思い浮かびます。)
メイソンウィーラー

@メイソン・ウィーラー。私の経験では、Open-Closedは言語に依存しません。JavaScriptまたはGoを使用して、オープンクローズデザインがどのように「意味のない」ものであるかについて、より具体的な例を提供する必要があります。おそらく、リスコフ置換はJavaScriptには適用されませんが、本質的なパターンであるポリモーフィズムは依然として適用されるようです。
S.Lott

@ S.Lott:編集の素晴らしい更新。元の回答よりもはるかに興味深いものでした。Pythonの間違いを修正していただきありがとうございます。一般に、特定のパターン例と、それらが動的言語、ポリモーフィズム、遅延バインディングなどに結び付く方法は完璧です。
ドメニック

@ S.Lott:Open / Closedは継承に関するもので、これらの言語にはありません。(また、オブジェクトが「変更のために閉じられている」という考えは、多くのRubyプログラマーと相性がよくありません...)
メイソンウィーラー

@Mason Wheeler:Open / Closedの説明をありがとう。JavaScriptの例外は重要だと思いますが、質問はとても開かれているので(JavaScript、Python、Ruby、およびETCと呼ばれる言語をリストしています)、特別なケースに対処する方法がわかりません。
S.Lott

8

Peter Norvigは1998年にこのまさに質問に答えました。彼が気付いた一連の詳細についてはhttp://norvig.com/design-patterns/ppframe.htmを、http://c2.com/cgi/wiki?AreDesignPatternsMissingLanguageFeaturesはポイントに関するさらなる議論。

短いバージョンは、あなたの言語がより多くの機能を持っているとき、繰り返しデザインパターンがより単純になる傾向があることです-多くの場合、目に見えないという点まで。彼は、これがGoFが特定したほとんどのデザインパターンに当てはまることを発見しました。


8

動的なオブジェクト指向言語でのプログラミングでは、同じパターンと原則の多くを使用しますが、環境によって特定の微調整と違いがあります。

インターフェイスをDuck Typingに置き換える -Gang of Fourが純粋な仮想関数で抽象基本クラスを使用するように指示し、Javaのインターフェイスを動的言語で使用する場合、理解する必要があるだけです。任意のオブジェクトをどこでも使用でき、実際に呼び出されるメソッドを実装すれば問題なく動作するため、正式なインターフェースを定義する必要はありません。実際に必要なものが明確になるように、ドキュメント化する価値があるかもしれません。

関数はオブジェクトでもあります-決定をアクションから分離することに関するパターンがたくさんあります。コマンド、戦略、責任の連鎖など。ファーストクラスの機能を備えた言語では、多くの場合、.doIt()メソッドを使用してオブジェクトを作成するのではなく、単に関数を渡すだけで十分です。これらのパターンは、「高次関数を使用する」に変換されます。

売却済み -インターフェースが存在しないため、インターフェース分離の原則がここで最大の打撃を受けます。それでも原則を検討する必要がありますが、コードにそれを具体化することはできません。ここであなたを守るのは個人的な警戒だけです。良い面としては、この原則に違反することによって引き起こされる痛みは、一般的な動的環境で大幅に軽減されます。

「...自分の特定の...イディオムで!」-各言語には良い習慣と悪い習慣があり、それらの言語で最高のコードが必要な場合は、それらを学習し、それらに従う必要があります。たとえば、リスト内包表記が組み込まれた言語では、完全に記述されたイテレータパターンが笑われる場合があります。


3

私の経験では、いくつかのパターンはまだPythonで有用であり、静的な言語よりも設定が簡単です。一部のパターンOTOHは、シングルトンパターンのように、必要とされないか、眉をひそめさえします。代わりにモジュールレベルの変数または関数を使用してください。または、Borg Patternを使用します。

Creational Patternを設定する代わりに、オブジェクトを作成するcallableを渡すだけで十分なことがよくあります。Python __call__には存在せずnew()、クラス自体の呼び出しであるため、関数、メソッドを持つオブジェクト、またはクラスである可能性があります。

def make_da_thing(maker, other, stuff):
    da_thing = maker(other + 1, stuff + 2)
    # ... do sth
    return da_thing

def maker_func(x, y):
     return x * y

class MakerClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
...
a = make_da_thing(maker_func, 5, 8)
b = make_da_thing(MakerClass, 6, 7)

状態と戦略パターンは、C ++やJavaなどの言語で非常によく似た構造を共有しています。Pythonではそうではありません。戦略パターンはほぼ同じままですが、状態パターンはほとんど不要になります。静的言語の状態パターンは、実行時のクラスの変更をシミュレートします。Pythonでは、まさにそれを行うことができます。実行時にオブジェクトのクラスを変更します。制御されたカプセル化された方法でそれを行う限り、大丈夫です:

class On(object):
    is_on = True
    def switch(self):
        self.__class__ = Off

class Off(object):
    is_on = False
    def switch(self):
        self.__class__ = On
...

my_switch = On()
assert my_switch.is_on
my_switch.switch()
assert not my_switch.is_on

Static Type Dispatchに依存するパターンは機能しないか、まったく異なる動作をします。たとえば、Visitor Pattern:などのボイラープレートコードを記述する必要はありません。JavaおよびC ++では、すべての訪問可能クラスでacceptメソッドを記述する必要がありますが、Pythonでは、Visitableなどのmixinクラスを通じてその機能を継承できます。

class Visitable(object):
    def accept(self, visitor):
        visit = getattr(visitor, 'visit' + self.__class__.__name__)
        return visit(self)
...

class On(Visitable):
    ''' exactly like above '''

class Off(Visitable):
    ''' exactly like above '''

class SwitchStatePrinter(object): # Visitor
    def visitOn(self, switch):
         print 'the switch is on'
    def visitOff(self, switch):
         print 'the switch is off'

class SwitchAllOff(object): # Visitor
    def visitOn(self, switch):
         switch.switch()
    def visitOff(self, switch):
         pass
...
print_state = SwitchStatePrinter()
turn_em_off = SwitchAllOff()
for each in my_switches:
    each.accept(print_state)
    each.accept(turn_em_off)

静的言語でのパターンの適用を必要とする多くの状況は、Pythonではそれほど多くありません。高階関数(デコレータ、関数ファクトリ)またはメタクラスなど、多くのことを他の手法で解決できます。


されています:私は今カバーamostあなたの答えている私は尋ねた質問実現上書き__class__Pythonで工場を実装するために良いアイデアを?
RDS
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.