特性和混入不是面向对象的

让我立刻说,我们将在这里讨论的功能是那些迫切需要进行放线手术的人带给面向对象编程的纯粹的毒药 ,就像David West在他的《 Objecting Thought》一书中所建议的那样。 这些功能具有不同的名称,但最常见的是traitsmixins 。 我很不明白,当具有这些功能时,如何仍然可以调用面向对象的编程。

Terry Gilliam的《拉斯维加斯的恐惧与厌恶》(1998年)

首先,简而言之就是它们的工作方式。 让我们使用Ruby模块作为示例实现。 假设我们有一堂课Book

class Book
  def initialize(title)
    @title = title
  end
end

现在,我们希望Book类使用一个静态方法(一个过程)来做一些有用的事情。 我们可以在实用程序类中定义它,然后让Book调用它:

class TextUtils
  def self.caps(text)
    text.split.map(&:capitalize).join(' ')
  end
end
class Book
  def print
    puts "My title is #{TextUtils.caps(@title)}"
  end
end

或者,我们可以使其变得更加“方便”,并extend我们的模块以便直接访问其方法:

module TextModule
  def caps(text)
    text.split.map(&:capitalize).join(' ')
  end
end
class Book
  extend TextModule
  def print
    puts "My title is #{caps(@title)}"
  end
end

如果您不了解面向对象的编程和静态方法之间的区别 ,那似乎很好。 而且,如果我们暂时忘记了OOP的纯度 ,即使我的字符较少,这种方法实际上对我来说也不太可读。 很难理解caps()方法从何而来,就像#{caps(@title)}而不是#{TextUtils.caps(@title)} 。 你不觉得吗

当我们include它们include进来时,Mixins开始发挥更好的作用。 我们可以将它们结合起来以构造我们要寻找的类的行为。 让我们创建两个mixin。 第一个称为PlainMixin ,它将按PlainMixin打印书的标题,第二个称为CapsMixin ,并大写已打印的内容:

module CapsMixin
  def to_s
    super.to_s.split.map(&:capitalize).join(' ')
  end
end
module PlainMixin
  def to_s
    @title
  end
end
class Book
  def initialize(title)
    @title = title
  end
  include CapsMixin, PlainMixin
  def print
    puts "My title is #{self}"
  end
end

没有附带的mixin的Call Book将按原样打印其标题。 添加include语句后, to_s的行为将被覆盖,方法print产生不同的结果。 我们可以组合mixin来产生所需的功能。 例如,我们可以再添加一个,将标题缩写为16个字符:

module AbbrMixin
  def to_s
    super.to_s.gsub(/^(.{16,}?).*$/m,'\1...')
  end
end
class Book
  def initialize(title)
    @title = title
  end
  include AbbrMixin, CapsMixin, PlainMixin
  def print
    puts "My title is #{self}"
  end
end

我确定您已经了解它们都可以访问Book类的私有属性@title 。 他们实际上可以完全使用课堂上的所有内容 。 从字面上看,它们是“代码片段”,我们将其注入到类中以使其更加强大和复杂。 这种方法有什么问题?

这与注解DTOgetter实用程序类相同 —它们将对象拆开并将功能块放置在对象看不到它们的地方。

对于mixin,该功能位于Ruby modules ,该modulesBook的内部结构进行了假设,并进一步假设程序员在内部结构更改后仍将了解Book的内容。 这样的假设完全违反了封装的思想。

mixins和对象私有结构之间的这种紧密耦合不会导致无法维护和难以理解的代码。

mixin的非常明显的替代品是可组合装饰器 。 看一下文章中给出的示例:

Text text = new AllCapsText(
  new TrimmedText(
    new PrintableText(
      new TextInFile(new File("/tmp/a.txt"))
    )
  )
);

它看起来与我们上面使用Ruby mixins所做的非常相似吗?

但是,与mixin不同,装饰器使对象较小且具有凝聚力,从而在它们之上分层附加功能。 Mixins的作用恰恰相反—它们使对象变得更复杂,并且因此使对象的可读性和可维护性降低。

老实说,我相信他们只是毒药。 发明它们的人距离理解面向对象设计的哲学还有很长的路要走。

您可能还会发现这些相关的帖子很有趣: 责任的纵向与横向分解复合名称是代码气味 ; 不变性的梯度 ; OOP中的反模式不可变对象如何具有状态和行为? ;

翻译自: https://www.javacodegeeks.com/2017/03/traits-mixins-not-oop.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值