Delegation委派:一个对象请求另一个对象的功能,在实体之间共享代码和数据的低级机制
委派是复用的一种常见形式
(1)显示委派:将发送对象传递给接收对象
(2)隐式委派:根据语言成员查找规则
委派模式:通过运行时动态绑定,实现对其他类中代码的动复用。
委派依赖于动态绑定,要求给定的方法调用可以在运行时调用不同的代码段。
接收方对象将操作委托给委托对象,接收方对象确保客户端不会滥用委托对象
所谓的动态绑定就是指程序执行期间(而不是在编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
用委托替换继承
子类只需要复用父类中的一小部分方法,可以不需要使用继承,而是通过委派机制来实现
Composite over inheritance principle
委派发生在object层面,继承发生在class层面
委派类型:
Use 使用(A使用B)
Association 关联(A has B)
Composition/aggregation 组成/聚合(A owns B)
耦合度:组合>聚合>关联>依赖
1、依赖---临时性的委派
一个类使用另一个类,但实际上没有将其合并为属性,可以是参数,也可以在方法中局部使用;如:类A当中使用了类B,其中类B是作为类A的方法参数、方法中的局部变量、或者静态方法调用 uses-a
依赖关系定义为:对于两个相对独立的对象,当一个对象负责构造 另一个对象的实例,或者依赖另一个对象的服务时,这两个对象之间主要体现为依赖关系。
此时,Flyable f 作为fly方法的形参
2、Association关联:永久性的委派
对象类之间的持久关系,允许一个对象实例使另一个对象实例代表其执行操作
一个类将另一个类作为属性/实例变量 has_a
上图中分别使用了成员变量形式和方法参数形式实现关联;
单向关联:类A中使用了类B,类B是作为类A的成员变量。
双向关联:类A中使用了类B作为成员变量;同时类B中也使用了类A作为成员变量。
3、Composition组合------难以变化
实现为一个对象包含另一个对象 is_part_of
组合关系中的成员变量一般都会在构造方法中赋值
public class People{
Soul soul;
Body body;
//组合关系中的成员变量一般会在构造方法中赋值
public People(Soul soul, Body body){
This.soul = soul;
This.body = body;
}
public void study(){
System.out.println(soul.getName());
}
public void eat(){
System.out.println(body.getName());
}
}
组合是一种耦合度更强的关联关系。存在组合关系的类表示“整体 -部分”的关联关系,“整体” 负责“部分”的生命周期,他们之间是共生共死的;并且“部分”单独存在时没有任何意义。
4、Aggregation聚合:可动态变化
对象存在于另一个对象之外,是在外部创建的,将它作为参数传递给构造函数; has_a
聚合是关联关系的一种耦合度强于关联,他们的代码表现是相同的,在语义上有区别
关联关系的对象间是相互独立的,聚合关系的对象之间存在包容关系,整体-个体
public class People{
Car car;
House house;
//聚合关系中作为成员变量的类一般使用set方法赋值
public void setCar(Car car){
This.car = car;
}
public void setHouse(House house){
This.house = house;
}
public void driver(){
System.out.println(car.getType());
}
public void sleep(){
System.out.println(house.getAddress());
}
}
聚合与组合区别:
(1)在组合中,当拥有的对象被销毁时,包含的对象也被销毁;而在聚合中未必
(2)聚合:整体-个体
组合:整体-部分
(上边聚合,下边组合)
四种委派类型都支持一对多的delegation
运用API和Frameworks设计系统级复用
公共API:要具有良好的设计,一旦发布就无法自由改变
白盒框架:通过子类化和重写方法进行扩展 继承
子类有主要的方法,给予了框架的控制
黑盒框架:通过实现一个插件接口来进行扩展 委派/组合
插件加载机制加载插件并对框架提供控制