什么OOP原则,如果有的话,不适用或应用不同的动态类型的环境,而不是静态类型的环境(例如Ruby C#)?这不是一场静态的与动态的辩论,而是我想知道,在分歧的任何一方,是否都有适用于一方而不是另一方的公认原则,还是适用不同的原则。像“喜欢构图而不是继承”这样的短语在静态类型的OOP文学中是众所周知的。它们是否同样适用于动态方面?
例如,在动态类型环境中,耦合的粒度似乎不会超过方法的级别。换句话说,任何给定的函数调用只会将调用者耦合到特定的接口,任何类都可能满足这个接口--或者换一种说法,任何像特定鸭子那样的功能。
另一方面,在Java中,耦合的粒度可以和包一样高。一个特定的方法调用不仅与另一个类/接口建立一个契约,而且还将它耦合到该类/接口的包/jar/程序集中。
这样的差异会导致不同的原则和模式吗?如果是的话,这些差异是否得到了阐明?红宝石镐书中有一个部分是朝这个方向发展的(鸭子输入/类不是类型),但我想知道是否还有其他的内容。我知道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发布于 2009-12-17 00:32:00
我认为,你所涉及到的本质区别是:
第一组中的语言倾向于动态类型,而不支持编译时检查接口,而第二组中的语言则倾向于静态类型,并支持编译时分块接口。
我想说的是,所有的OO原则都适用于两者,但是
编辑
所以为了回答你最初的问题,我检查了
http://c2.com/cgi/wiki?PrinciplesOfObjectOrientedDesign
和
http://www.dofactory.com/patterns/Patterns.aspx
在实践中,在一个系统中,由于各种好的原因(当然还有一些不好的原因),没有遵循OO原则。好的理由包括:性能比纯粹的设计质量考虑更多;替代结构/命名的文化利益超过纯设计质量关注的地方;实现某一特定语言非标准方式功能的额外工作的成本超过纯设计的好处。
抽象工厂、生成器、工厂方法、原型、适配器、策略、命令链、桥、代理、观察者、访问者甚至MVC/MMVM等粗粒度模式在小型系统中的使用往往较少,因为代码的通信量较少,因此创建此类结构的好处并不大。
更细粒度的模式,如State、Command、Factory方法、Composite、Decorator、Facade、Fly权重、Memento、Template方法在第1组代码中可能更常见,但通常几种设计模式并不适用于这样的对象本身,而是应用于对象的不同部分,而在第2组中,代码模式往往基于每个对象的一种模式出现。
在大多数第一组语言中,把所有的全局数据和函数看作是一种单例的“应用”对象是很有意义的。我知道我们正在模糊过程编程和OO编程之间的界线,但是在很多情况下,这种代码肯定像一个"Application“对象!)
一些非常细粒度的设计模式,如Iterator,倾向于构建到第1组语言中。
发布于 2009-12-16 22:50:13
首先,我要说的是,不适用于动态和静态类型语言的OOP原则并不是一个原则。
尽管如此,以下是一个例子:
接口隔离原则(http://objectmentor.com/resources/articles/isp.pdf)指出,客户端应该依赖于满足其需要的最具体的接口。如果客户端代码需要使用C类的两种方法,那么C应该实现接口,我只包含这两种方法,客户机将使用I而不是C。在不需要接口的动态类型化语言中,这个原则是无关的(因为接口定义的类型和类型不需要在变量没有类型的语言中)
编辑
第二个例子-依赖反转原理(http://objectmentor.com/resources/articles/dip.pdf)。这个原则是“依赖于接口或抽象函数和类,而不是依赖于具体的函数和类的策略”。同样,在动态类型化语言中,客户端代码不依赖于任何东西--它只是指定方法签名--从而消除了这一原则。
第三个例子- Liskov替代原理(http://objectmentor.com/resources/articles/lsp.pdf)。此原则的教科书示例是一个Square类,它子类为矩形类。然后,在矩形变量上调用setWidth()方法的客户端代码在改变高度时会感到惊讶,因为实际的对象是平方。同样,在动态类型语言中,变量是无类型的,在客户端代码中不会提到矩形类,因此不会出现这样的意外情况。
发布于 2010-12-30 09:21:35
我对所有这些都有一个“激进”的观点:在我看来,在数学的支持下,OOP对于任何有趣的问题都不适用于静态类型的环境。我将有趣定义为所涉及的意义、抽象关系。这可以很容易地证明(见“协方差问题”)。
这个问题的核心是OOP的概念承诺它是一种建模抽象的方法,并与通过静态类型传递的契约编程相结合,如果不打破封装,就不能实现关系。只要尝试任何协变二进制操作符就可以看到:尝试在C++中实现“小于”或“添加”。您可以很容易地对基本抽象进行编码,但无法实现它。
在动态系统中,没有高级别的形式化类型,也没有任何封装,因此OO实际上可以工作,特别是基于原型的系统,比如原始Smalltalk,实际上交付的工作模型根本无法在静态类型约束下进行编码。
用另一种方式回答这个问题:这个问题的基本假设本质上是有缺陷的。OO没有任何一致的原则,因为它不是一个一致的理论,因为它不存在任何模型,有足够的力量来处理除了简单的编程任务之外的任何事情。不同的是您放弃了什么:在动态系统中,您放弃了封装,在静态系统中,您只需切换到工作的模型(函数编程、模板等),因为所有静态类型的系统都支持这些功能。
https://stackoverflow.com/questions/1918310
复制相似问题