Role

理解角色

有些问题需要在其他不相关的对象之间共享行为。这种公共行为对类来说是正交的,他是对象所扮演的角色。当之前无关的对象开始扮演某个公共的角色时,他们便与自己扮演的角色所对应的对象之间建立了一层关系,这些关系与经典继承要求的子类/父类关系有所不同,他们不可见,但又确实存在。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Schedule
def scheduled?(schedulable, start_date, end_date)
puts "this #{schedulable.class} is not schedulable between #{start_date} and #{end_date}"
false
end
end

module Schedulable
attr_writer :schedule

def schedulable?(start_date, end_date)
!scheduled?(start_date - lead_days, end_date)
end


def scheduled?(start_date, end_date)
schedule.scheduled?(self, start_date, end_date)
end

def lead_days
0
end
end


class Bicycle
include Schedulable

def lead_days
1
end

# ......
end

class Vehicle
include Schedulable

def lead_days
3
end

# ......
end

编写可替代性的代码

识别出反模式

  1. 使用类似 typecategory 这类名字的变量来确定发送给self的是何种消息的对象,会包含两个高度相关但又有所不同的对象。
  2. 当某个发送对象要检查接受对象的类以确定所发送的消息时,你一定忽略了某个鸭子类型的存在。
  3. 除了共享接口,鸭子类型也可能共享行为。

坚持抽象

  1. 抽象父类里的所有代码都应该适用于每一个继承它的类;
  2. 错误的抽象会导致继承对象不正确的行为;

重视契约

里氏替换原则: 对于一个健全的类型系统,其子类必须能够替换他的父类型。

使用模板方法模式

用于创建可继承代码的基本编码技术是模板方法模式。这种模式可以让你将抽象与具体分离开来。抽象代码用于定义算法,具体代码可以继承这个抽象,并通过改写这些模板方法来提供特殊化。

预先将类解耦

尽量避免编写继承者需要发送super消息的代码。可以通过钩子消息让子类参与进来,同时还可免除它们要知道抽象算法的职责。

创建浅层结构

钩子方法的局限性在于它仅适用于创建浅层结构。深层次结构的问题在于,他们定义了一条很长的用于消息查找的搜索路径,并且为对象提供了大量的机会,让他们在那条路径上可以随着消息的传递添加行为。因为对象依赖于它之上的所有事物,所以深层次的结构拥有一个很大的内奸依赖关系集合。深层次结构的另外一个问题在于程序员往往只是对处于顶端和底部的类比较熟悉。

Donate article here