Dav*_*ims 10 oop design-patterns static-typing dynamic-typing static-language
OOP原则(如果有的话)在动态类型环境中不适用或应用不同,而不是静态类型环境(例如Ruby vs C#)?这不是对静态与动态辩论的呼吁,而是我想看看是否存在适用于一方而非另一方适用于该范围的任何一方的公认原则,或者采用不同的方式.在"静态类型"OOP文献中,诸如"喜欢组合到继承"的短语是众所周知的.它们是否适用于动态方面?
例如,在动态类型环境中,似乎耦合的粒度不会超过方法的级别.换句话说,任何给定的函数调用只将调用者耦合到任何类可能满足的特定接口- 或者换句话说,任何像那个特定的鸭子那样嘎嘎叫的东西.
另一方面,在Java中,耦合的粒度可以与包一样高.一个特定的方法调用不仅与另一个类/接口建立契约,而且还将它耦合到该类/接口的package/jar/assembly中.
像这样的差异会产生不同的原则和模式吗?如果是这样,这些差异是否明确表达了?Ruby Pickaxe书中有一节向这个方向发展(Duck Typing/Classes Are 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
Run Code Online (Sandbox Code Playgroud)
我认为你所触及的本质区别是:
语言组1.在调用object.method1,object.method2,object.method3时调用的实际方法可以在对象的生命周期内更改.
语言组2.在调用object.method1,object.method2,object.method3时调用的实际方法在对象的生命周期内不能更改.
组1中的语言往往具有动态类型,并且不支持编译时检查的接口,组2中的语言往往具有静态类型并支持编译时chcked接口.
我会说所有OO原则都适用于两者,但是
在组1中可能需要一些额外的(显式)编码来实现(运行时而不是编译时)检查,以断言为了满足接口契约而使用所有适当的方法创建新对象,因为没有编译时接口协议检查,(如果你想使第1组代码更像组2)
第2组中可能需要一些额外的编码来模拟为方法调用调用的实际方法的更改,方法是使用额外的状态标志来调用子方法,或者在引用附加的几个对象之一时包装方法或一组方法到主对象,其中几个对象中的每一个都有不同的方法实现,(如果你想使第2组代码更像组1代码)
第2组语言中对设计的限制使它们更适合于那些易于沟通(而不是理解)变得更加重要的大型项目
第1组语言中对设计缺乏限制使得小型项目更好,程序员可以更容易地检查各种设计管道约束是否因为代码较小而一目了然
从另一组语言中制作代码很有意思且非常值得研究,但语言差异的关键在于它们如何帮助不同规模的团队( - 我相信!:))
还有其他各种不同之处
根据所涉及的确切原则,可能需要或多或少的腿部工作来用一种语言或另一种语言实现OO设计.
编辑
所以为了回答你原来的问题,我进行了检查
http://c2.com/cgi/wiki?PrinciplesOfObjectOrientedDesign
和
http://www.dofactory.com/patterns/Patterns.aspx
在实践中,系统中没有遵循面向对象原则的各种原因(当然也有一些不好).很好的理由包括性能问题超过纯粹的设计质量问题,在替代结构/命名的文化优势超过纯设计质量问题的地方,以及以特定语言的标准方式实现功能的额外工作的成本超过了纯粹的设计.
像抽象工厂,构建器,工厂方法,原型,适配器,策略,命令链,桥,代理,观察者,访问者甚至MVC/MMVM这样的粗粒度模式往往在小型系统中使用较少,因为关于代码较少,因此创建此类结构的好处并不多.
像State,Command,Factory Method,Composite,Decorator,Facade,Flyweight,Memento,Template方法这样的细粒度模式在组1代码中可能更常见,但是通常有几种设计模式不适用于对象,而是应用于不同的部分.一个对象,而在组2中,代码模式往往存在于每个对象的一个模式上.
恕我直言,在大多数第1组语言中,将所有全局数据和函数视为一种单独的"应用程序"对象是很有意义的.我知道我们正在模糊Procedural和OO编程之间的界限,但这种代码在很多情况下肯定像"应用程序"对象一样嘎嘎作响!:)
像Iterator这样的一些非常细粒度的设计模式往往被构建到第1组语言中.