静的に型付けされた環境(RubyとC#など)とは対照的に、動的に型付けされた環境では、どのOOP原則が適用されたり、異なって適用されたりしませんか?これは静的対動的な議論の呼びかけではありませんが、どちらか一方に適用され、他方には適用されない、どちらかの側に受け入れられた原則があるかどうか、または異なる方法で適用されるかどうかを確認したいと思います。「継承よりも構成を優先する」などのフレーズは、静的に型付けされたOOPの文献でよく知られています。それらは動的な側面にも同じように適用できますか?
たとえば、動的に型付けされた環境では、結合の粒度はメソッドのレベルを超えないように見えます。言い換えると、特定の関数呼び出しは、呼び出し元をその特定のインターフェイスに結合するだけです。これは、クラスが満たす可能性があります。言い換えると、特定のアヒルのように鳴くものはすべてです。
一方、Javaでは、結合の粒度はパッケージと同じくらい高くなる可能性があります。特定のメソッド呼び出しは、別のクラス/インターフェースとのコントラクトを確立するだけでなく、それをそのクラス/インターフェースのパッケージ/jar/アセンブリに結合します。
このような違いは、異なる原則とパターンを生み出しますか?もしそうなら、これらの違いは明確にされていますか?Ruby Pickaxeの本には、この方向に少し進むセクションがあります(Duck Typing / Classes Are n't Types)が、他に何かあるのではないかと思います。Rubyのデザインパターンを知っていますが、読んでいません。
編集-Liskovは静的環境と同じように動的環境に適用しないと主張されてきましたが、私はそれが適用されると考えずにはいられません。一方では、クラス全体との高レベルの契約はありません。しかし、特定のクラスへのすべての呼び出しは、リスコフが規定する方法で子クラスが満たす必要がある暗黙のコントラクトを構成するのではありませんか?次のことを考慮してください。「いくつかのバーのことをする」の呼び出しは、子クラスが参加する必要がある契約を作成します。これは「特殊なオブジェクトを基本クラスのように扱う」場合ではありませんか?
class Bartender
def initialize(bar)
@bar = bar
end
def do_some_bar_stuff
@bar.open
@bar.tend
@bar.close
end
end
class Bar
def open
# open the doors, turn on the lights
end
def tend
# tend the bar
end
def close
#clean the bathrooms
end
end
class BoringSportsBar < Bar
def open
# turn on Golden Tee, fire up the plasma screen
end
def tend
# serve lots of Bud Light
end
end
class NotQuiteAsBoringSportsBar < BoringSportsBar
def open
# turn on vintage arcade games
end
end
class SnootyBeerSnobBar < Bar
def open
# replace empty kegs of expensive Belgians
end
def tend
# serve lots of obscure ales, porters and IPAs from 124 different taps
end
end
# monday night
bartender = Bartender.new(BoringSportsBar.new)
bartender.do_some_bar_stuff
# wednesday night
bartender = Bartender.new(SnootyBeerSnobBar.new)
bartender.do_some_bar_stuff
# friday night
bartender = Bartender.new(NotQuiteAsBoringSportsBar.new)
bartender.do_some_bar_stuff