目录
适配器模式
简介
角色
使用
优缺点
使用场景
装饰器模式
简介
优缺点
模式结构
使用
使用场景
适配器模式
简介
允许将不兼容的对象包装成一个适配器类,使得其他类可以通过适配器类与原始对象进行交互,从而提高兼容性
角色
目标角色:该角色定义把其他类转换为何种接口,也就是我们的期望接口
源角色:你想把谁转换成目标角色,这个“谁”就是源角色,它是已经存在的、运行良好的类或对象
适配器角色:适配器模式的核心角色,其他两个角色都是已经存在的角色,而适配器角色是需要新建立的,它的职责非常简单:通过继承或是类关联的方式把源角色转换为目标角色
使用
1.定义目标接口:创建一个目标接口,这个接口定义了客户端所期望的功能。
2.创建原始类:客户端原始功能
3.创建适配器类:创建一个适配器类,该类实现了目标接口,同时包装了不兼容的原始对象,使得客户端可以通过目标接口与原始对象进行交互
4.使用目标接口:客户端代码使用目标接口与适配器进行交互
// 目标接口
interface Target {
void request();
}
// 原始类
class Adaptee {
void specificRequest() {
System.out.println("Adaptee's specific request.");
}
}
// 适配器类
class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.request();
}
}
目标接口Target
,它定义了一个request
方法。我们还有一个原始类Adaptee
,它有一个名为specificRequest
的方法。我们的适配器类Adapter
实现了目标接口,并且包装了原始类的specificRequest
方法。在客户端代码中,我们创建了一个原始类的实例和一个适配器类的实例,然后将适配器类的实例传递给目标接口的引用。当我们调用目标接口的request
方法时,实际上是适配器类在调用原始类的specificRequest
方法
优缺点
优点:
1.能提高类的透明性和复用,现有的类复用但不需要改变。
2.目标类和适配器类解耦,提高程序的扩展性。
3.在很多业务场景中符合开闭原则
缺点:
1.适配器编写过程需要全面考虑,可能会增加系统的复杂性
2.增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱
使用场景
1.一个类的接口转换成期望的另一个接口,使不能兼容的两个类一起工作
2.想要创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作
3.在软件维护期间,由于不同产品或不同厂家造成功能类似而接口不相同的情况,可以通过适配器模式来解决
使用适配器模式可以降低不同组件之间的耦合度,提高系统的可扩展性和可维护性。同时,适配器模式还可以解决不同系统之间的接口不兼容问题
装饰器模式
简介
在不改变现有对象结构下,动态的给对象添加一些功能
优缺点
优点
1.装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
2.通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
3.装饰器模式完全遵守开闭原则
缺点
装饰器模式会增加许多子类,过度使用会增加程序得复杂性
模式结构
角色:
抽象构件角色:定义一个抽象接口以规范准备接收附加责任的对象
具体构件角色:实现抽象构件,通过装饰角色为其添加一些职责
抽象装饰角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能
具体装饰角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任
结构图:
使用
1.创建接口
public interface Shape {
double getArea();
}
2.接口具体实现类
public class Rectangle implements Shape {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public double getArea() {
return length * width;
}
}
3.创建抽象装饰器
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape shape) {
this.decoratedShape = shape;
}
@Override
public double getArea() {
return decoratedShape.getArea();
}
}
4.创建具体装饰器
public class RectangleWithBorder extends ShapeDecorator {
private double borderWidth;
public RectangleWithBorder(Shape shape, double borderWidth) {
super(shape);
this.borderWidth = borderWidth;
}
@Override
public double getArea() {
return decoratedShape.getArea() + borderWidth * decoratedShape.getArea();
}
}
5.使用
public class Main {
public static void main(String[] args) {
Shape rectangle = new Rectangle(5, 5);
Shape rectangleWithBorder = new RectangleWithBorder(rectangle, 1); // 给矩形添加边框宽度为1的装饰器
System.out.println("Rectangle area: " + rectangle.getArea()); // 输出:Rectangle area: 25.0
System.out.println("Rectangle with border area: " + rectangleWithBorder.getArea()); // 输出:Rectangle with border area: 27.0
}
}
使用场景
1.扩展功能:当您想要扩展一个类的功能时,可以使用装饰器模式来添加新的责任,而不需要修改原有类的代码。这使得代码更加灵活,易于维护
2.动态变化:如果需要在运行时根据需要动态地改变对象的行为,可以使用装饰器模式
3.统一接口:如果有一组具有相似功能但是又不完全相同的类,可以使用装饰器模式来统一它们的接口,使得在使用它们时不需要关心具体的类
4.延迟加载:如果某些数据是可选的,可以在需要时才加载,使用装饰器模式可以实现延迟加载的功能
5.处理复杂对象:当涉及到复杂的对象结构时,装饰器模式可以简化代码。通过将不同的行为封装到不同的装饰器中,可以组合这些装饰器来创建具有不同行为的对象
装饰器模式适用于在不修改原有代码的基础上,动态地给对象添加新的行为。它适用于需要在运行时动态地改变对象行为或者需要统一接口的场景。