首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >OOP和动态类型(不是静态还是动态)

OOP和动态类型(不是静态还是动态)
EN

Stack Overflow用户
提问于 2009-12-16 22:37:02
回答 4查看 2.3K关注 0票数 10

什么OOP原则,如果有的话,不适用或应用不同的动态类型的环境,而不是静态类型的环境(例如Ruby C#)?这不是一场静态的与动态的辩论,而是我想知道,在分歧的任何一方,是否都有适用于一方而不是另一方的公认原则,还是适用不同的原则。像“喜欢构图而不是继承”这样的短语在静态类型的OOP文学中是众所周知的。它们是否同样适用于动态方面?

例如,在动态类型环境中,耦合的粒度似乎不会超过方法的级别。换句话说,任何给定的函数调用只会将调用者耦合到特定的接口,任何类都可能满足这个接口--或者换一种说法,任何像特定鸭子那样的功能。

另一方面,在Java中,耦合的粒度可以和包一样高。一个特定的方法调用不仅与另一个类/接口建立一个契约,而且还将它耦合到该类/接口的包/jar/程序集中。

这样的差异会导致不同的原则和模式吗?如果是的话,这些差异是否得到了阐明?红宝石镐书中有一个部分是朝这个方向发展的(鸭子输入/类不是类型),但我想知道是否还有其他的内容。我知道Ruby中的设计模式,但还没看过。

编辑--有人认为,利斯科夫在动态环境中的应用与在静态环境中的应用不同,但我不禁认为它适用于动态环境。一方面,不存在与整个类的高级合同。但是,不是所有对任何给定类的调用都构成了一个隐式契约,需要按照Liskov规定的方式由子类来满足吗?请考虑以下几点。在“做一些酒吧的事情”中的调用创建了一个需要由子类来处理的契约。这不是一种“将特定对象当作基类处理”的情况吗?

代码语言:javascript
运行
复制
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
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-12-17 00:32:00

我认为,你所涉及到的本质区别是:

  • 语言组1.调用object.method1、object.method2、object.method3时调用的实际方法在对象的生存期内可能发生变化。
  • 语言组2.调用object.method1、object.method2、object.method3时调用的实际方法在对象生存期内不能更改。

第一组中的语言倾向于动态类型,而不支持编译时检查接口,而第二组中的语言则倾向于静态类型,并支持编译时分块接口。

我想说的是,所有的OO原则都适用于两者,但是

  • 在第1组中可能需要一些额外(显式)代码来实现(运行时而不是编译时)检查,以断言使用所有适当方法创建新对象以满足接口契约,因为没有编译时接口协议检查(如果您希望使第1组代码更像组2)。
  • 在第2组中可能需要进行一些额外的编码,以便通过使用额外的状态标志来调用子方法来建模方法调用的实际方法的更改,或者将方法或一组方法封装在对附加到主对象的几个对象的引用中,其中每个对象都有不同的方法实现,(如果您想使第2组代码更像组1代码)
  • 在第2组语言中,对设计的限制使它们更适合于更大的项目,在这些项目中,沟通的方便(相对于理解)变得更加重要。
  • 在第1组语言中缺乏对设计的限制使得更适合于较小的项目,在这些项目中,程序员可以更容易地检查各种设计管道约束是否仅仅因为代码较小而得到满足。
  • 从一组语言(如另一组语言)中编写代码很有趣,值得研究,但语言差异的关键在于它们对不同规模的团队有多大的帮助(-我相信!:)
  • 还有各种各样的不同之处
  • 使用一种或另一种语言实现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组语言中。

票数 5
EN

Stack Overflow用户

发布于 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()方法的客户端代码在改变高度时会感到惊讶,因为实际的对象是平方。同样,在动态类型语言中,变量是无类型的,在客户端代码中不会提到矩形类,因此不会出现这样的意外情况。

票数 3
EN

Stack Overflow用户

发布于 2010-12-30 09:21:35

我对所有这些都有一个“激进”的观点:在我看来,在数学的支持下,OOP对于任何有趣的问题都不适用于静态类型的环境。我将有趣定义为所涉及的意义、抽象关系。这可以很容易地证明(见“协方差问题”)。

这个问题的核心是OOP的概念承诺它是一种建模抽象的方法,并与通过静态类型传递的契约编程相结合,如果不打破封装,就不能实现关系。只要尝试任何协变二进制操作符就可以看到:尝试在C++中实现“小于”或“添加”。您可以很容易地对基本抽象进行编码,但无法实现它。

在动态系统中,没有高级别的形式化类型,也没有任何封装,因此OO实际上可以工作,特别是基于原型的系统,比如原始Smalltalk,实际上交付的工作模型根本无法在静态类型约束下进行编码。

用另一种方式回答这个问题:这个问题的基本假设本质上是有缺陷的。OO没有任何一致的原则,因为它不是一个一致的理论,因为它不存在任何模型,有足够的力量来处理除了简单的编程任务之外的任何事情。不同的是您放弃了什么:在动态系统中,您放弃了封装,在静态系统中,您只需切换到工作的模型(函数编程、模板等),因为所有静态类型的系统都支持这些功能。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1918310

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档