design-patterns - OOP和动态键入(不是静态还是动态)

标签 design-patterns oop static-typing dynamic-typing static-language

什么样的OOP原则(如果有的话)在动态类型的环境中与静态类型的环境(例如Ruby vs C#)相对应?这不是呼吁进行静态还是动态辩论,而是我想看看在这种划分的任何一方是否都存在接受的原则,它们适用于一个而不适用于另一方,或者适用于其他方面。在静态类型的OOP文献中,诸如“优先考虑组成而不是继承”这样的短语是众所周知的。它们在动态方面是否同样适用?

例如,在动态类型的环境中,似乎耦合的粒度不超过方法的级别。换句话说,任何给定的函数调用只会将调用者耦合到该特定接口(interface),任何类都可能满足-换句话说,就是像该特定鸭子那样发出嘎嘎声的任何东西。

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

这样的差异会引起不同的原理和模式吗?如果是这样,这些差异是否已明确表达? Ruby Pickaxe书中有一个部分朝这个方向发展(鸭打字/类不是类型),但是我想知道是否还有其他内容。我知道Design Patterns in Ruby,但尚未阅读。

编辑-有人争辩说Liskov在动态环境中的应用与在静态环境中的应用不同,但是我不禁认为它确实适用。一方面,没有与整个类(class)的高层契约(Contract)。但是,不是所有对任何给定类的调用都构成了隐式契约,子类需要像Liskov所规定的那样满足隐式契约吗?考虑以下。 “做一些吧东西”中的调用创建了一个契约(Contract),子类需要遵守该契约(Contract)。这不是“像对待基类一样处理专用对象”的情况吗?

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

最佳答案

我认为您要触及的本质区别是:

  • 语言组1。调用object.method1,object.method2,object.method3时调用的实际方法可以在对象的生存期内更改。
  • 语言组2。调用object.method1,object.method2,object.method3时调用的实际方法在对象的生存期内无法更改。

  • 组1中的语言趋向于具有动态类型并且不支持编译时检查的接口(interface),组2中的语言趋向于具有静态类型并支持编译时经过检查的接口(interface)。

    我想说所有面向对象的原理都适用于这两种方法,但是
  • 在第1组中可能需要一些额外的(显式)代码来实现(运行时而不是编译时)检查,以断言使用所有适当的方法创建新对象以满足接口(interface)协定,因为没有编译-时间接口(interface)协议(protocol)检查,(如果要使第1组代码更像第2组)
  • 在第2组中可能需要一些额外的编码,以通过使用额外的状态标志来调用子方法来模拟为方法调用而调用的实际方法的变化,或者在引用多个对象之一的过程中包装该方法或一组方法附加到主对象上,其中几个对象中的每个对象具有不同的方法实现,(如果要使第2组代码更像第1组代码)
  • 第2组语言对设计的严格限制使它们更适合大型项目,在这些项目中,易于交流(而非理解)变得更加重要
  • 第1组语言中对设计的缺乏限制使小型项目更好,程序员可以更轻松地检查一下是否满足各种设计管道约束,这仅仅是因为代码较小的
  • 用一种和另一种语言来编写代码很有趣并且值得研究,但是语言差异的重点确实在于它们如何帮助不同规模的团队(-我相信!:))
  • 其他各种差异
  • 可能需要某种或多种方式来实现一种或多种语言的OO设计,具体取决于所涉及的原理。


  • 编辑

    因此,为了回答您的原始问题,我检查了

    http://c2.com/cgi/wiki?PrinciplesOfObjectOrientedDesign



    http://www.dofactory.com/patterns/Patterns.aspx

    在实践中,出于各种良好的原因(当然也有一些不好的理由),系统中并未遵循OO原则。充分的理由包括:性能方面的关注胜过纯设计质量的关注,替代结构/命名的文化 yield 超过纯设计质量的关注,以及以某种非特定语言的标准方式实现功能的额外工作的成本超过了纯语言的 yield 。一个纯净的设计。

    诸如抽象工厂,构建器,工厂方法,原型(prototype),适配器,策略,命令链,网桥,代理,观察者,访客甚至MVC/MMVM等较粗粒度的模式在小型系统中往往较少使用,因为有关代码较少,因此创建此类结构的好处不是很大。

    在第1组代码中,更细粒度的模式(例如状态,命令,工厂方法,复合,装饰器,外观,Flyweight,内存,模板方法)可能更常见,但通常有几种设计模式不适用于这样的对象,而不适用于对象的不同部分一个对象,而在第2组中,代码模式倾向于以每个对象一个模式为基础。

    恕我直言,在大多数第1组语言中,将所有全局数据和功能视为一种单例“应用程序”对象是很有意义的。我知道我们将要模糊过程和OO编程之间的界线,但是在很多情况下,这种代码肯定像“Application”对象一样嘎嘎作响! :)

    诸如Iterator之类的一些非常细粒度的设计模式倾向于内置到第1组语言中。

    关于design-patterns - OOP和动态键入(不是静态还是动态),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1918310/

    相关文章:

    design-patterns - 如何在 Swift 中将对象映射到枚举而不引发异常

    grails - 从其他数据源获取信息以在Grails上更新我自己的信息

    wpf - 通过服务保存时如何保持模型一致?

    java - 为什么类型声明在静态类型语言中很重要?

    static-typing - 您知道动态类型语言中优雅解决方案的任何示例吗?

    python - 是否有从协程端点返回值的标准方法

    design-patterns - 通过数据访问层处理多个数据库的设计模式?

    Java OOP,如何将具有多个列表类型字段的类设计为单个类?

    c++ - 处理对象组的设计模式

    Kotlin - `if` 和 `when` 表达式的类型