与静态类型环境(例如 Ruby 与 C#)相比,哪些 OOP 原则(如果有)在动态类型环境中不适用或应用方式不同?这不是要求进行静态与动态辩论,而是我想看看在该分歧的任何一方是否有公认的原则适用于一方而不适用于另一方,或者适用不同的原则。在静态类型的 OOP 文献中,诸如“更喜欢组合而不是继承”之类的短语是众所周知的。它们是否同样适用于动态方面?
例如,在动态类型环境中,耦合的粒度似乎不超过方法的级别。换句话说,任何给定的函数调用只会将调用者耦合到任何类都可能满足的特定接口 - 或者换句话说,任何像特定鸭子一样嘎嘎叫的东西。
另一方面,在 Java 中,耦合的粒度可以与包一样高。一个特定的方法调用不仅与另一个类/接口建立契约,而且还将它耦合到该类/接口的包/jar/程序集中。
这样的差异会导致不同的原则和模式吗?如果是这样,这些差异是否已经阐明?Ruby Pickaxe书中有一个部分朝这个方向发展(Duck Typing/Classes Aren't Types),但我想知道是否还有其他内容。我知道Ruby 中的设计模式,但还没有读过。
编辑——有人认为Liskov在动态环境中的应用与在静态环境中的应用不同,但我不禁认为它确实如此。一方面,整个班级没有高级别的合同。但是,不是所有对任何给定类的调用都构成了一个隐式契约,需要按照 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