GoF之适配器模式、策略模式详解
适配器模式(Adapter Pattern)
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
优点
1、可以让任何两个没有关联的类一起运行。
2、提高了类的复用。
3、增加了类的透明度。
4、灵活性和扩展性都非常好,符合“开闭原则”。
缺点:
1、过多地使用适配器,会让系统变复杂。比如,明明看到调用的是A 接口,其实内部被适配成了 B 接口的实现。如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
2.由于 JAVA至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。
类适配器模式(adapter pattern)
具体实现:通过电源适配器,将电源输入220V(适配者)转换为5V输出(目标)。
//目标角色
public interface PowerTarget{
public int output5V();
}
//适配者角色
public class PowerAdaptee{
private int output = 220;
public int output220V() {
System.out.println("电源输出电压:" + output);
return output;
}
}
//适配器角色
public class PowerAdapterextends PowerAdapteeimplements PowerTarget{
@Override
public int output5V() {
int output =output220V();
System.out.println("电源适配器开始工作,此时输出电压是:" + output);
output = 5;
System.out.println("电源适配器工作完成,此时输出电压是:" + output);
return output;
}
}
电源适配器类实现了电源目标,继承了适配者。
//类适配器模式测试
public class ClassAdapterPatternTest{
public static void main(String[] args) {
PowerTargettarget = new PowerAdapter();
target.output5V();
}
}
对象适配器模式(object adapter pattern)
对象适配器模式在运行时实现target(目标)接口。在这种适配器模式中,适配器包装了一个类实例。适配器通过调用包装对象实例的方法实现适配。
代码示例和类适配器模式只有Adapter类有不同,其他都一样,只贴上Adapter类。
//适配器角色
public class PowerAdapterimplements PowerTarget{
private PowerAdaptee powerAdaptee;
public PowerAdapter(PowerAdapteepowerAdaptee) {
super();
this.powerAdaptee = powerAdaptee;
}
@Override
public int output5V() {
int output = powerAdaptee.output220V();
System.out.println("电源适配器开始工作,此时输出电压是:" + output);
output = 5;
System.out.println("电源适配器工作完成,此时输出电压是:" + output);
return output;
}
}
实现了PowerTarget(目标角色),在创建对象时引入PowerAdaptee(适配者角色)。
缺省适配器模式(defaultadapter pattern)(客户端,继承b,调用b中的方法,不必直接实现a(直接实现a需要实现a中的所有的方法))
当不需要全部实现接口提供的方法时,可以设计一个适配器抽象类实现接口,并为接口中的每个方法提供默认方法,抽象类的子类就可以有选择的覆盖父类的某些方法实现需求,它适用于一个接口不想使用所有的方法的情况。
在java8后,接口中可以有default方法,就不需要这种缺省适配器模式了。接口中方法都设置为default,实现为空,这样同样同样可以达到缺省适配器模式同样的效果。
策略模式(Strategy Pattern)也叫 政策模式(Policy Pattern)。
指的是对象具备某个行为,但是在不同的场景中,该行为有不同的实现算法。比如一个人的交税比率与他的工资有关,不同的工资水平对应不同的税率。
优点:
1、算法可以自由切换。
2、避免使用多重条件判断。
3、扩展性良好。
缺点:
1、策略类会增多。
2、所有策略类都需要对外暴露。
具体实现:建立加减乘算法族,解决在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。
//创建一个接口,定策略或算法的行为。
public interface Strategy{
public int doOperation(int num1, int num2);
}
//创建实现接口的实体类,里面包含具体的策略或算法实现。利用多态,使行为在不同场景下产生不同结果。
public class OperationAddimplements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationSubstractimplements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
public class OperationMultiplyimplements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
//创建Context类,用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;
public class Context {
private Strategy strategy;
public Context(){
}
public SetStrategy(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
//使用 Context 来查看当它改变策略 Strategy 时的行为变化。
public class StrategyPatternClient{
public static void main(String[] args) {
Contextcontext = new Context();
context.SetStrategy(new OperationAdd());
System.out.println("10 + 5 =" + context.executeStrategy(10, 5));
context.SetStrategy(new OperationSubstract());
System.out.println("10 - 5 =" + context.executeStrategy(10, 5));
context.SetStrategy(new OperationMultiply());
System.out.println("10 * 5 =" + context.executeStrategy(10, 5));
}
}
输出结果:
10 + 5 = 15
10 - 5 = 5
10 * 5 =50
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
原文:https://mp.weixin.qq.com/s/g20WQyzJNmvkH-kLPZRYBA
作者:专注一行代码
来源:微信公众号