设计模式:结构型

发布时间 2023-03-27 16:51:08作者: 夏末-LateSummer

适配器模式(Adapter Pattern)

适配器模式是一种结构型设计模式,用于将一个类的接口转换为客户端所期望的另一种接口,以便可以使用不兼容的类协同工作。

适配器模式包含三个核心角色:

  • 目标接口(Target):客户端所期望的接口。
  • 源接口(Adaptee):需要被转换的接口。
  • 适配器(Adapter):将源接口转换成目标接口的类。

电压转换的例子:

 1 public class Adaptee {
 2 
 3     public int output220v() {
 4         return 220;
 5     }
 6 
 7 }
 8 
 9 public interface Target {
10 
11     int output5v();
12 
13 }
14 
15 
16 public class Adapter implements Target {
17     private Adaptee adaptee;
18 
19     public Adapter(Adaptee adaptee) {
20         this.adaptee = adaptee;
21     }
22 
23     @Override
24     public int output5v() {
25         int i = adaptee.output220v();
26         System.out.println(String.format("原始电压:%d v -> 输出电压:%d v", i, 5));
27         return 5;
28     }
29 
30 }
31 
32 
33 public class UseAdapter {
34 
35     public static void main(String[] args) {
36         Adaptee adaptee = new Adaptee();
37         Target target = new Adapter(adaptee);
38         target.output5v();
39     }
40 
41 }

解决的问题:适配器模式主要解决两个不兼容接口之间的转换问题。

例如,一个系统需要使用一个新的日志框架,但是原有的代码使用的是旧的日志框架,这时可以使用适配器模式。可以创建一个适配器类,该类实现新的日志框架的接口,并在其内部调用旧的日志框架的接口。这样,原有的代码就可以使用新的日志框架了,而不需要修改原有的代码。

第一,确定目标接口

系统原来的日志接口如下

1 public interface LogFactory {
2     void debug(String tag,String message);
3 }

 第二,三方库接口及实现

下面是第三方库提供的日志功能,但是其接口与二狗他们系统目前使用的不兼容。

 1 public interface NbLogger {
 2     void d(int priority, String message, Object ... obj);
 3 }
 4 //具体提供日志功能的实现类
 5 public class NbLoggerImp implements NbLogger {
 6     @Override
 7     public void d(int priority, String message, Object... obj) {
 8         System.out.println(String.format("牛逼logger记录:%s",message));
 9     }
10 }

 第三,构建适配器类

这个类是适配器模式的核心,通过此类就可以将三方库提供的接口转换为系统的目标接口

 1 public class LogAdapter implements LogFactory {
 2     private NbLogger nbLogger;
 3 
 4     public LogAdapter(NbLogger nbLogger) {
 5         this.nbLogger = nbLogger;
 6     }
 7 
 8     @Override
 9     public void debug(String tag, String message) {
10         Objects.requireNonNull(nbLogger);
11         nbLogger.d(1, message);
12     }
13 }

 LogAdapter 实现了系统的目标接口,同时持有三方库NbLogger的引用。

第四,客户端使用

public class AdapterClient {
    public void recordLog() {
        LogFactory logFactory = new LogAdapter(new NbLoggerImp());
        logFactory.debug("Test", "我将使用牛逼logger打印log");
    }
}

 可以看到,通过适配器客户端就可以很轻松的切换到新的日志系统了。

桥接模式(Bridge Pattern)

桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分和实现部分分离开来,以便两者可以独立地变化。桥接模式的核心思想是将一个系统分成多个维度,每个维度单独考虑,从而简化系统,提高可扩展性和可维护性。 

桥接模式所涉及的角色有:

  • Abstraction:抽象类
  • RefinedAbstraction:扩充抽象类
  • Implementor:实现类接口
  • ConcreteImplementor:具体实现类 

举个例子,假设有一个形状接口 Shape 和一个颜色接口 Color,如果需要实现各种形状和各种颜色的组合,传统的做法是定义大量的子类,如 RedCircle、GreenCircle、BlueCircle、RedRectangle、GreenRectangle、BlueRectangle 等等。而使用桥接模式,可以把形状和颜色分别抽象出来,分别作为抽象类 Shape 和 Color 的实现类,然后将它们组合起来即可,如 RedCircle、GreenRectangle 等等。这样,在新增一种形状或颜色时,只需要新增一个实现类即可,不需要修改现有的代码,从而提高了代码的可扩展性和维护性。这里是一个简单的 Java 代码示例,演示了如何使用桥接模式来实现 Shape 和 Color 的组合,而不需要定义大量的子类:

 1 // 定义颜色接口
 2 public interface Color {
 3     void fill();
 4 }
 5 
 6 // 实现 Red Color
 7 public class Red implements Color {
 8 
 9     @Override
10     public void fill() {
11         System.out.println("Filling with red color...");
12     }
13 }
14 
15 // 实现 Green Color
16 public class Green implements Color {
17 
18     @Override
19     public void fill() {
20         System.out.println("Filling with green color...");
21     }
22 }
23 
24 // 定义形状抽象类
25 public abstract class Shape {
26     protected Color color;
27 
28     public Shape(Color color) {
29         this.color = color;
30     }
31 
32     abstract void draw();
33 }
34 
35 // 实现 Circle 形状
36 public class Circle extends Shape {
37 
38     public Circle(Color color) {
39         super(color);
40     }
41 
42     @Override
43     void draw() {
44         System.out.print("Drawing circle with ");
45         color.fill();
46     }
47 }
48 
49 // 实现 Rectangle 形状
50 public class Rectangle extends Shape {
51 
52     public Rectangle(Color color) {
53         super(color);
54     }
55 
56     @Override
57     void draw() {
58         System.out.print("Drawing rectangle with ");
59         color.fill();
60     }
61 }
62 
63 // 测试
64 public class BridgePatternDemo {
65 
66     public static void main(String[] args) {
67         Color red = new Red();
68         Shape circle = new Circle(red);
69         circle.draw();
70 
71         Color green = new Green();
72         Shape rectangle = new Rectangle(green);
73         rectangle.draw();
74     }
75 }

组合模式(Composite Pattern)

组合模式是一种结构型设计模式,它将对象组织成树形结构,使得客户端可以以一致的方式处理单个对象和对象组合。

组合模式由以下两种对象组成:

  1. 叶子节点:表示树形结构中的单个对象。
  2. 组合节点:表示树形结构中的对象组合,它可以包含其他组合节点和叶子节点。

组合模式的核心思想是将对象组织成树形结构,并且让客户端能够以一致的方式处理单个对象和对象组合。这种结构可以使得客户端将组合对象和单个对象一视同仁,从而简化了客户端的代码。此外,组合模式还可以通过递归方式访问整个树形结构,使得我们可以方便地对树形结构中的对象进行操作。

一个常见的例子是文件系统,文件系统由目录和文件两种元素组成,目录可以包含子目录和文件,而文件只能包含数据。

我们可以使用组合模式来构建文件系统的结构。首先定义一个抽象类 AbstractFile,表示文件和目录的基类,包含了一些基本的操作方法。然后定义 File 类和 Directory 类,分别表示文件和目录。Directory 类维护了一个子节点的列表,可以添加、删除子节点,以及对子节点进行操作。这样就可以通过组合方式来构建出任意复杂的目录结构。

示例代码如下:

 1 // 抽象文件类
 2 abstract class AbstractFile {
 3     public abstract void add(AbstractFile file);
 4     public abstract void remove(AbstractFile file);
 5     public abstract AbstractFile getChild(int index);
 6     public abstract void operation();
 7 }
 8 
 9 // 文件类
10 class File extends AbstractFile {
11     private String name;
12     
13     public File(String name) {
14         this.name = name;
15     }
16     
17     public void add(AbstractFile file) {
18         System.out.println("不支持该方法");
19     }
20     
21     public void remove(AbstractFile file) {
22         System.out.println("不支持该方法");
23     }
24     
25     public AbstractFile getChild(int index) {
26         System.out.println("不支持该方法");
27         return null;
28     }
29     
30     public void operation() {
31         System.out.println("访问文件 " + name);
32     }
33 }
34 
35 // 目录类
36 class Directory extends AbstractFile {
37     private List<AbstractFile> files = new ArrayList<>();
38     private String name;
39     
40     public Directory(String name) {
41         this.name = name;
42     }
43     
44     public void add(AbstractFile file) {
45         files.add(file);
46     }
47     
48     public void remove(AbstractFile file) {
49         files.remove(file);
50     }
51     
52     public AbstractFile getChild(int index) {
53         return files.get(index);
54     }
55     
56     public void operation() {
57         System.out.println("访问目录 " + name);
58         for (AbstractFile file : files) {
59             file.operation();
60         }
61     }
62 }

 使用组合模式可以方便地构建出任意复杂的文件系统结构,增加、删除和操作文件和目录也十分简单。

装饰者模式(Decorator Pattern)

外观模式(Facade Pattern)

享元模式(Flyweight Pattern)

动态代理模式(Proxy Pattern)