概述
- 代理模式:代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。
- 装饰器模式:装饰者模式在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器的嵌套使用。
- 适配器模式:适配器模式是一种事后的补救策略。适配器提供跟原始类不同的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。
代理模式
它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。
- 一般情况下,让代理类和原始类实现同样的接口
- 如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的,可以通过让代理类继承原始类的方法来实现代理模式
- 常用在业务系统中开发非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志等
- 将附加功能与业务功能解耦,放到代理类统一处理,方便让程序员只关注业务方面的开发
// author: suoxd123@126.com
public interface IRunner{
// 接口也可以替换成抽象类
void run();
}
public class Marathon : IRunner {
public void run() { //... }
}
public class CrossCountryProxy : IRunner {
private IRunner runner;
public CrossCountryProxy(IRunner runner) {
this.runner = runner;
}
public void run() {
// 新添加的代理逻辑
runner.run();
// 新添加的代理逻辑
}
}
装饰器模式
装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能,这也是判断是否该用装饰器模式的一个重要的依据。
从代码看,两种模式完全一样,只是其设计的侧重点不同,简单来讲:
- 代理:偏重因自己无法完成或自己无需关心,需要他人干涉事件流程。
- 装饰:偏重对原对象功能的扩展,扩展后的对象仍是是对象本身。
// author: suoxd123@126.com
public interface IRunner{
// 接口也可以替换成抽象类
void run();
}
public class Marathon : IRunner {
public void run() { //... }
}
public class CrossCountryDecorator : IRunner {
private IRunner runner;
public CrossCountryDecorator(IRunner runner) {
this.runner = runner;
}
public void run() {
// 功能增强代码
runner.run();
// 功能增强代码
}
}
适配器模式
用来做适配的,它将不兼容的接口转换为可兼容的接口,常用有两种实现方式:
- 类适配器:使用继承关系来实现
- 对象适配器:使用组合关系来实现
判断使用哪个的标准一般有两个,一个是 Adaptee 接口的个数,另一个是 Adaptee 和 ITarget 的契合程度
- 如果 Adaptee 接口并不多,那两种实现方式都可以。
- 如果 Adaptee 接口很多,而且 Adaptee 和 ITarget 接口定义大部分都相同,那我们推荐使用类适配器,因为 Adaptor 复用父类 Adaptee 的接口,比起对象适配器的实现方式,Adaptor 的代码量要少一些。
- 如果 Adaptee 接口很多,而且 Adaptee 和 ITarget 接口定义大部分都不相同,那我们推荐使用对象适配器,因为组合结构相对于继承更加灵活。
使用适配器模式的场景一般有以下5种情况:
- 封装有缺陷的接口设计
- 统一多个类的接口设计
- 替换依赖的外部系统
- 兼容老版本接口
- 适配不同格式的数据
// author: suoxd123@126.com
public interface IRunner {
void walk();
void run();
}
public class CrossCountry {
public void run(){}
public void eat(){}
}
// 类适配器: 基于继承
public class SportsAdaptor : CrossCountry, IRunner {
public void walk() {
super.eat();
//其它行为
}
// 跟对象适配器最大的不同点:
// 这里run可以不实现,直接继承自CrossCountry
}
// 对象适配器:基于组合
public class SportsAdaptor : IRunner {
private CrossCountry crossCountry;
public Adaptor(CrossCountry crossCountry) {
this.crossCountry = crossCountry;
}
public void walk() {
this.crossCountry.eat(); //委托给Adaptee
//其它行为
}
//这里run需要显示实现
public void run() {
this.crossCountry.run();
}
}
网友评论