# 结构型模式
作者:Ethan.Yang
博客:https://blog.ethanyang.cn (opens new window)
相关代码参考: 设计模式代码仓库 (opens new window)
# 代理模式
代理模式是一种结构型设计模式,其核心思想是:为其他对象提供一种代理,以控制对这个对象的访问。
# 模式定义与角色
代理模式主要包含以下三个角色:
- 抽象主题(Subject) 定义代理类和真实主题类的公共接口,可以是接口或抽象类。
- 真实主题(Real Subject) 也称“被代理类”,负责实现真实的业务逻辑。
- 代理主题(Proxy) 内部持有真实主题的引用,负责控制访问,并可增强功能。
当无法或不想直接引用某个对象或访问某个对象存在困难时,可以通过也给代理对象来间接访问。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。
# 代理模式的实现
代理类的生成方式不同,分为:
- 静态代理:代理类由开发者编写,编译期确定。
- 动态代理:运行时动态生成代理类,常见的实现有 JDK 动态代理 和 CGLIB 动态代理。
# 1. 静态代理
抽象主题
public interface Person {
void findLove();
}
2
3
4
真实主题
@Data
public class ZhangSan implements Person {
@Override
public void findLove() {
System.out.println("寻到真爱, 要求女");
}
}
2
3
4
5
6
7
8
代理主题角色
public class ZhangSanFather implements Person{
private ZhangSan zhangSan;
@Override
public void findLove() {
System.out.println("替儿子物色对象");
zhangSan.findLove();
System.out.println("张三笑嘻嘻");
}
}
2
3
4
5
6
7
8
9
10
11
# 2. 动态代理 jdk实现
动态代理有很多API, 先用基于JDK的动态代理对代码改造, 实现一个中介角色, 毕竟不是每一个征婚人都是老登儿子
抽象主题
public interface Person {
void findLove();
}
2
3
4
真实主题
@Data
public class ZhangSan implements Person {
@Override
public void findLove() {
System.out.println("寻到真爱, 要求女");
}
}
2
3
4
5
6
7
8
代理主题角色
public class MeiPo implements InvocationHandler {
private Person target;
public Person getInstance(Person target) {
this.target = target;
Class<? extends Person> clazz = target.getClass();
return (Person) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.target, args);
after();
return result;
}
private void before() {
System.out.println("收到征婚请求, 收集女性单身角色");
}
private void after() {
System.out.println("双方同意, 结婚");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
测试:
public class Test {
public static void main(String[] args) {
MeiPo meiPo = new MeiPo();
Person zs = meiPo.getInstance(new ZhangSan());
zs.findLove();
}
}
2
3
4
5
6
7
8
# 3. 动态代理 cglib实现
真实主题
public class Customer {
public void findLove() {
System.out.println("儿子要求:肤白貌美大长腿");
}
}
2
3
4
5
6
代理主题
public class CglibMeiPo implements MethodInterceptor {
public Object getInstance(Class<?> clazz) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void before(){
System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
System.out.println("开始物色");
}
private void after(){
System.out.println("OK的话,准备办事");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 门面模式
又叫做外观模式, 提供了一个统一的接口, 用来访问子系统中的一群接口, 主要特点是定义一个高层接口让子系统更容易使用。
# 模式定义与角色
- Facade(门面类):客户端访问子系统的唯一入口。
- 子系统(SubSystem):实现具体功能,Facade 调用它们完成工作。
# 门面模式的实现
子系统角色
public class SubSystemA {
public void doA() {
System.out.println("doing A stuff");
}
}
public class SubSystemB {
public void doB() {
System.out.println("doing B stuff");
}
}
public class SubSystemC {
public void doC() {
System.out.println("doing C stuff");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
门面系统
public class Facade {
private SubSystemA a = new SubSystemA();
private SubSystemB b = new SubSystemB();
private SubSystemC c = new SubSystemC();
// 对外接口
public void doA() {
this.a.doA();
}
public void doB() {
this.b.doB();
}
public void doC() {
this.c.doC();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 装饰器模式
又称包装模式,在不改变原有对象结构的基础上,动态地扩展对象功能。比继承更灵活,适用于功能扩展频繁变化的场景。
# 模式定义与角色
Component(抽象组件):定义对象的接口,是被装饰对象的统一规范。
ConcreteComponent(具体组件):实现 Component 接口,表示被装饰的原始对象。
Decorator(抽象装饰器):实现 Component 接口,持有一个 Component 对象引用,定义通用的装饰逻辑结构。
ConcreteDecorator(具体装饰器):继承 Decorator,实现具体的扩展功能。
# 装饰器模式的实现
以饮品咖啡为例
抽象组件(如果只定义行为规范,优先使用接口;若需共享部分默认实现,再使用抽象类。)
public interface Drink { String getDes(); Double cost(); }1
2
3
4
5
6具体组件
public class CoffeeDrink implements Drink { @Override public String getDes() { return "coffee"; } @Override public Double cost() { return 1.0; } }1
2
3
4
5
6
7
8
9
10
11
12抽象装饰器
public abstract class CoffeeDecorator implements Drink { private Drink drink; public CoffeeDecorator(Drink drink) { this.drink = drink; } @Override public String getDes() { return this.drink.getDes(); } @Override public Double cost() { return this.drink.cost(); } protected abstract String doSomething(); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20具体装饰器
public class CoffeeMilkDecorator extends CoffeeDecorator { public CoffeeMilkDecorator(Drink drink) { super(drink); } @Override protected String doSomething() { return ""; } @Override public Double cost() { return super.cost() + 1; } @Override public String getDes() { return super.getDes() + " 加牛奶"; } } public class CoffeeSugarDecorator extends CoffeeDecorator { public CoffeeSugarDecorator(Drink drink) { super(drink); } @Override public String getDes() { return super.getDes() + " 加糖"; } @Override public Double cost() { return super.cost() + 1; } @Override protected String doSomething() { return ""; } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44测试
public class Test { public static void main(String[] args) { Drink drink = new CoffeeDrink(); drink = new CoffeeMilkDecorator(drink); drink = new CoffeeSugarDecorator(drink); System.out.println(drink.cost()); System.out.println(drink.getDes()); } }1
2
3
4
5
6
7
8
9
10
11
# 享元模式
享元模式是一种结构型设计模式,适用于当系统中存在大量对象时,为减少内存开销而复用对象的场景。它通过将对象的状态划分为内部状态(Intrinsic State)与 外部状态(Extrinsic State),将不可变的内部状态共享存储,避免重复创建,实现对象复用,达到提升系统性能的目的。
享元模式可以看作是一种缓存池(Object Pool)机制,其核心思想是在工厂方法(Factory Method)的基础上加入了对象缓存功能。
# 模式定义与角色
Flyweight(抽象享元角色) 定义享元对象的接口,规定内部状态与外部状态的操作方式。
ConcreteFlyweight(具体享元角色) 实现 Flyweight 接口,封装内部状态,不应包含会改变共享状态的行为。
FlyweightFactory(享元工厂) 管理享元对象的创建与缓存,确保相同内部状态的对象只创建一次。
# 享元模式的实现
抽象享元角色
public interface Font { void display(String character, int size); }1
2
3
4具体享元角色
public class ConcreteFont implements Font { private final String fontName; // 内部状态:字体名称 public ConcreteFont(String fontName) { this.fontName = fontName; } @Override public void display(String character, int size) { System.out.println("字符:" + character + " 使用字体:" + fontName + ",字号:" + size); } }1
2
3
4
5
6
7
8
9
10
11
12
13享元工厂
public class FontFactory { private static final Map<String, Font> fontPool = new HashMap<>(); public static Font getFont(String fontName) { if (!fontPool.containsKey(fontName)) { fontPool.put(fontName, new ConcreteFont(fontName)); } return fontPool.get(fontName); } }1
2
3
4
5
6
7
8
9
10
11测试案例
public class Test { public static void main(String[] args) { Font font1 = FontFactory.getFont("宋体"); Font font2 = FontFactory.getFont("宋体"); Font font3 = FontFactory.getFont("黑体"); font1.display("你", 12); font2.display("好", 14); font3.display("!", 16); System.out.println("font1 和 font2 是同一个对象吗?" + (font1 == font2)); // true } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 组合模式
组合模式(Composite Pattern),又称为整体-部分模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
# 模式定义与角色
- 抽象构件(Component):定义组合中对象的接口,可以是抽象类或接口,提供公共操作。
- 叶子构件(Leaf):叶子节点对象,表示树的最小单元,无子节点。
- 容器构件(Composite):容器节点,维护子节点集合,实现对子节点的添加、删除等操作。
# 组合模式的实现
透明组合模式: 透明组合模式是把所有公共方法都定义在component中, 客户端不需要区分树 叶结点, 具备完全一致的接口。
抽象根节点
public abstract class FileComponent { protected String name; public FileComponent(String name) { this.name = name; } public abstract void display(); // 以下是透明组合模式的关键:所有方法都放在抽象类中 public void add(FileComponent component) { throw new UnsupportedOperationException("不支持添加操作"); } public void remove(FileComponent component) { throw new UnsupportedOperationException("不支持移除操作"); } public List<FileComponent> getChildren() { throw new UnsupportedOperationException("不支持获取子节点"); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23叶子节点
public class FileLeaf extends FileComponent { public FileLeaf(String name) { super(name); } @Override public void display() { System.out.println("文件: " + name); } }1
2
3
4
5
6
7
8
9
10
11树枝节点
public class Folder extends FileComponent { private List<FileComponent> children = new ArrayList<>(); public Folder(String name) { super(name); } @Override public void display() { System.out.println("文件夹: " + name); for (FileComponent child : children) { child.display(); } } @Override public void add(FileComponent component) { children.add(component); } @Override public void remove(FileComponent component) { children.remove(component); } @Override public List<FileComponent> getChildren() { return children; } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32测试
public class Test { public static void main(String[] args) { FileComponent root = new Folder("根目录"); FileComponent doc = new Folder("文档"); FileComponent pic = new Folder("图片"); FileComponent file1 = new FileLeaf("简历.docx"); FileComponent file2 = new FileLeaf("说明.pdf"); FileComponent image1 = new FileLeaf("照片.jpg"); doc.add(file1); doc.add(file2); pic.add(image1); root.add(doc); root.add(pic); root.display(); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
安全组合模式, 只规定系统各个层次的最基础的一致行为, 把组合(树结点)本身的方法放到自身当中。
抽象根节点
public interface FileComponent { void display(); }1
2
3叶子节点
public class FileLeaf implements FileComponent { private String name; public FileLeaf(String name) { this.name = name; } @Override public void display() { System.out.println("文件: " + name); } }1
2
3
4
5
6
7
8
9
10
11
12
13树枝节点
public class Folder implements FileComponent { private String name; private List<FileComponent> children = new ArrayList<>(); public Folder(String name) { this.name = name; } public void add(FileComponent component) { children.add(component); } public void remove(FileComponent component) { children.remove(component); } public List<FileComponent> getChildren() { return children; } @Override public void display() { System.out.println("文件夹: " + name); for (FileComponent child : children) { child.display(); } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28测试
public class Test { public static void main(String[] args) { Folder root = new Folder("根目录"); Folder doc = new Folder("文档"); Folder pic = new Folder("图片"); FileLeaf file1 = new FileLeaf("简历.docx"); FileLeaf file2 = new FileLeaf("说明.pdf"); FileLeaf image1 = new FileLeaf("照片.jpg"); doc.add(file1); doc.add(file2); pic.add(image1); root.add(doc); root.add(pic); root.display(); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 适配器模式
适配器模式又叫做变压器模式, 功能是将一个类的接口变成客户端所期望的另一接口, 从而使接口不匹配的2个类可以一起工作。
# 模式定义与角色
- 目标角色(Target): 我们期望的接口
- 源角色(Adaptee): 存在于系统中, 内容满足客户需求但接口不匹配的接口实例
- 适配器(Adapter): 将源角色转换为目标角色的类实例
# 适配器形式
类适配器
通过继承实现适配器功能, 让Adapter实现Target接口, 并继承Adaptee
源角色
public class Adaptee { public void oldMethod() { System.out.println("Adaptee: 旧接口中的方法"); } }1
2
3
4
5
6目标角色
public interface Target { void newMethod(); }1
2
3
4适配器
public class Adapter extends Adaptee implements Target{ @Override public void newMethod() { System.out.println("Adapter 将 oldMethod 转为 newMethod"); oldMethod(); } }1
2
3
4
5
6
7
8测试
public class Test { public static void main(String[] args) { Adapter adapter = new Adapter(); adapter.newMethod(); } }1
2
3
4
5
6
7
对象适配器
通过组合来实现适配器的功能, 让Adapter实现Target接口, 然后内部持有Adaptee实例, 在Target接口方法内部进行转换
更改适配器实现
public class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void newMethod() { System.out.println("Adapter 将 oldMethod 转为 newMethod"); adaptee.oldMethod(); } }1
2
3
4
5
6
7
8
9
10
11
12
13接口适配器
主要是解决接口方法过多, 如果直接实现接口, 类会多出许多空实现的方法
源角色
public class Adaptee extends Adapter { @Override public void method1() { System.out.println("实现 method1"); } }1
2
3
4
5
6
7目标角色
public interface Target { void method1(); void method2(); void method3(); void method4(); }1
2
3
4
5
6
7
8
9
10适配器(利用抽象类实现默认方法 子类实现自己需要的方法)
public abstract class Adapter implements Target { @Override public void method1() { } @Override public void method2() { } @Override public void method3() { } @Override public void method4() { } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 桥接模式
将抽象部分与它的具体实现部分分离, 使其可以独立的变化, 通过组合的方式建立两个类之间的联系, 类似于多继承但是维持了类的单一职责原则
# 模式定义与角色
- 抽象: 该类持有一个对实现角色的引用, 抽象角色的方法需要实现角色自己实现
- 修正抽象: 抽象的具体实现, 对抽象的方法进行完善和扩展
- 实现: 确定实现维度的基本操作, 提供给抽象使用
- 具体实现: 实现的具体实现
# 桥接模式的实现
实现层
public interface OperatingSystem { void run(); }1
2
3具体实现
public class IOS implements OperatingSystem { @Override public void run() { System.out.println("运行 iOS 系统"); } } public class AndroidOS implements OperatingSystem { @Override public void run() { System.out.println("运行 Android 系统"); } }1
2
3
4
5
6
7
8
9
10
11
12
13抽象
public abstract class Phone { protected OperatingSystem operatingSystem; public Phone(OperatingSystem operatingSystem) { this.operatingSystem = operatingSystem; } public abstract void start(); }1
2
3
4
5
6
7
8
9
10修正抽象
public class XiaoMiPhone extends Phone { public XiaoMiPhone(OperatingSystem operatingSystem) { super(operatingSystem); } @Override public void start() { System.out.print("小米手机 -> "); operatingSystem.run(); } } public class HuaWeiPhone extends Phone { public HuaWeiPhone(OperatingSystem operatingSystem) { super(operatingSystem); } @Override public void start() { System.out.print("华为抽象 -> "); operatingSystem.run(); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25测试
public class Test { public static void main(String[] args) { Phone phone1 = new XiaoMiPhone(new AndroidOS()); phone1.start(); // 输出:小米手机 -> 运行 Android 系统 Phone phone2 = new HuaWeiPhone(new IOS()); phone2.start(); // 输出:华为手机 -> 运行 iOS 系统 } }1
2
3
4
5
6
7
8
9
10