设计可复用的类
Liskov替换原则(LSP)
Let q(x) be a property provable about objects x of type T, then q(y) should be provable for objects y of type S where S is a subtype of T.
– Barbara Liskov
1 | Animal a = new Animal(); |
在可以使用a的场景,都可以用c1和c2代替而不会有任何问题。
Liskov替换原则是衍生子类需要遵循的重要原则,它使得客户端可用统一的方式处理不同类型的对象,LSP要求子类相对于父类具有:
- 更强的不变量
- 更弱的前置条件
- 更强的后置条件
注:更强的后置条件要求子类型中不能产生新的异常。
父类与子类的衔接类似于一个漏斗。
委派(Delegation)与组合(Composition)
A simple Delegation example
B类为对A类的一个委派,在B类中的私有字段a绑定了一个A类,B类的foo操作被委派给绑定的a来做:
1 | class A { |
建立绑定关系:
1 | A a = new A(); |
Delegation vs Inheritance
From GeeksforGeeks
Delegation is simply passing a duty off to someone/something else.
- Delegation can be an alternative to inheritance.
- Delegation means that you use an object of another class as an instance variable, and forward messages to the instance.
- It is better than inheritance for many cases because it makes you to think about each message you forward, because the instance is of a known class, rather than a new class, and because it doesn’t force you to accept all the methods of the super class: you can provide only the methods that really make sense.
- Delegation can be viewed as a relationship between objects where one object forwards certain method calls to another object, called its delegate.
- The primary advantage of delegation is run-time flexibility – the delegate can easily be changed at run-time. But unlike inheritance, delegation is not directly supported by most popular object-oriented languages, and it doesn’t facilitate dynamic polymorphism.
Delegation可以作为继承的一个替代品,它最主要的优点是灵活。相比于继承,它不需要继承另一个类的所有方法,而是可以通过委派机制调用部分方法;同时它支持类的动态绑定。
Delegation发生在object层面,Inheritance发生在class层面。
几类常见Delegation
Dependency: 临时性的delegation
Dependency在调用函数时传入delegation类,并将操作委派给传入的类处理,是一种临时的delegation关系。
类与被委派的类之间的关系为uses-a。
1 | Flyable f = new FlyWithWings(); |
Duck类的定义如下:1
2
3
4
5class Duck {
void fly(Flyable f) {
f.fly();
}
}
Association: 永久性的delegation
Association是一种永久的delegation关系,delegation关系通过将被委派的类存入字段的方式来实现。
类与被委派的类之间的关系为has-a。
1 | Flyable f = new FlyWithWings(); |
Duck类的定义如下:1
2
3
4
5
6
7
8
9
10
11
12class Duck {
Flyable f;
void Duck(Flyable f) {
this.f = f;
}
void setFlyBehavior(Flyable f) {
this.f = f;
}
void fly() {
f.fly();
}
}
Composition: 更强的association
Composition与Association类似,均将delegation关系存入字段。但不同之处在于Composition将委派关系的绑定写入了代码,在运行时委派关系不可变。
被委派的类与类之间的关系为is_part_of
1 | Duck d = new Duck(); |
Duck类的定义如下:1
2
3
4
5
6class Duck {
Flyable f = new FlyWithWings();
void fly() {
f.fly();
}
}
Aggregation: 更弱的 association
Aggregation与Composition类似,均将delegation关系存入字段。与Composition的不同之处在于委派关系在运行时可变。
Aggregation与Composition还具有以下不同:Aggregation关系中的两个类不具有相互依存关系,而Composition中的两个类具有依附关系,即如果A has-a B,那么B不能脱离A存在。