首先,我们先以一个例子来引入委托(Delegation)这个概念,以下是两套代码:
/* Version A */
static void sort(int [] list, boolean ascending) {
...
boolean mustSwap;
if (ascending) {
mustSwap = list[i] < list[j];
} else {
mustSwap = list[i] > list[j];
}
...
}
/* Version B*/
interface Comparator {
boolean compare(int i, int j);
}
final Comparator ASCENDING = (i, j) -> i < j;
final Comparator DESCEDING = (i, j) -> i > j;
static void sort(int [] list, Comparator cmp) {
...
boolean mustSwap = cmp.compare(list[i], list[j]);
...
}
在Version A 中,我们使用了基础的排序的代码,而Version B中,定义了一个Comparator的接口,使得sort方法与该接口有了依赖关系,这就是委托(delegation)。
Comparator接口
实现Comparator接口以实现排序时的大小比较
Comparable接口
该接口给所有实现它的对象提供了一个整体的排序,这个顺序被视为该类的基础排序,需要实现的compareTo方法也被视为该类的基础比较方法。
与Comparator的区别:不需要新建Comparator类注意:这个不是委托
委托
委托就是一个对象请求另一个对象的功能,它是复用的一种常见形式。
委托分为显性委托与隐性委托两种。
以下为委托的例子:
委托模式是一种使用委托的设计模式,通过运行时动态绑定,实现对其他类中的代码进行动态复用。
过程
- 接收对象将一些操作委托给委托对象。
- 接收对象应保证客户端不会错误使用委托对象
示意图如下:
使用委托
考虑一个能够输出log的List
public interface List<E> { //初始List
public boolean add(E e);
public E remove(int index);
public void clear();
...
}
public class LoggingList<E> implements List<E> {
private final List<E> list;
public LoggingList<E>(List<E> list) { // 动态绑定
this.list = list;
}
public boolean add(E e) {
System.out.println("Adding " + e);
return list.add(e); // 功能委托
}
public E remove(int index) {
System.out.println("Removing at " + index);
return list.remove(index); // 功能委托
}
}
委托与继承
在设计中,常常会使用继承与委托相结合的方式
若子类只需要复用父类中的一小部分方法,则一个较优的方法是使用委托而不是使用继承,因为继承会耗费更多的资源,出现大量无用的方法。
复合重用原则(CRP)
其核心思想是将一些功能一致的子功能(属性和方法)合成为一个单独的模块(类),然后在主类中调用这个模块即可。复用合成原则能够为需求变更带来很大的设计灵活性,同时也能够有效地降低主类的复杂度,在实际的项目中应该充分利用。委托发生在object层面,而继承发生在class层面。
举例说明:例如现在有一个Car
类,包含很多功能,如刹车、油门等,但现在科技发展的很快,出现了自动驾驶的新技术,为了应用这个新技术,我们可以在Car
类中添加一个selfDrive()
方法以实现自动驾驶,这样虽然能应用自动驾驶,但在生产的时候,为了区分能自动驾驶的汽车与不能自动驾驶的汽车,可能需要开多条生产线,一旦市场需求发生变化,由于生产线的成本较高,生产调整往往不能够及时响应。所以,这时候合成复用原则就起作用了,我们仍然只有一条生成线,但是增加了一个自动驾驶的模块,如Autonomous
类。这个类定义与自动驾驶的所有属性和操作方法,然后将其添加至Car
的派生类中即可。