GoF之适配器模式、策略模式详解

go (32) 2024-02-24 11:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说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

作者:专注一行代码

来源:微信公众号

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

发表回复