设计模式

装饰器模式

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你动态地为对象添加新的行为,而不改变其结构或影响其他对象。这种模式通过将对象放入一个“包装器”(即装饰器对象)中,以便在保持原始对象类型不变的情况下,扩展或修改其行为。

  • 对象组合:装饰器模式依赖于对象组合(composition),而不是继承(inheritance)。你可以将一个对象嵌套在另一个对象中,从而添加额外的功能。
  • 遵循接口:装饰器和被装饰对象通常都实现相同的接口或继承相同的父类,因此可以互换使用。
  • 动态扩展:装饰器模式可以在运行时为对象添加新的功能,而不像继承那样在编译时就固定了行为。

下面是一个装饰器模式的示例代码

1
2
3
4
5
// 咖啡的基础接口
interface Coffee {
String getDescription();
double getCost();
}
1
2
3
4
5
6
7
8
9
10
11
12
// 具体的基础咖啡实现(被修饰的对象)
class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}

@Override
public double getCost() {
return 5.0; // 基础咖啡的价格
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 咖啡装饰器基类(装饰器的抽象类)
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;

public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}

@Override
public String getDescription() {
return decoratedCoffee.getDescription();
}

@Override
public double getCost() {
return decoratedCoffee.getCost();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 牛奶装饰器(装饰器的实现类)
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}

@Override
public String getDescription() {
return decoratedCoffee.getDescription() + ", Milk";
}

@Override
public double getCost() {
return decoratedCoffee.getCost() + 1.5; // 加牛奶的费用
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 糖装饰器(装饰器的实现类)
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}

@Override
public String getDescription() {
return decoratedCoffee.getDescription() + ", Sugar";
}

@Override
public double getCost() {
return decoratedCoffee.getCost() + 0.5; // 加糖的费用
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 主程序
public class CoffeeShop {
public static void main(String[] args) {
// 创建一个基础咖啡
Coffee coffee = new SimpleCoffee();

// 加牛奶
coffee = new MilkDecorator(coffee);

// 加糖
coffee = new SugarDecorator(coffee);

// 输出描述和价格
System.out.println("Description: " + coffee.getDescription());
// Description: Simple Coffee, Milk, Sugar
System.out.println("Cost: $" + coffee.getCost());
// Cost: $7.0
}
}

UML

DecoratorUML

summary

被修饰的是一个接口(coffee)的实现类(SimpleCoffee),装饰类的基类是CoffeeDecorator,两个装饰器分别是MilkDecoratorSugarDecorator

在这个场景下,MilkDecoratorSugarDecorator装饰了SimpleCoffee,扩展了它的功能而且并没有改变被修饰类的结构和继承关系。

适配器模式

适配器模式(Adapter Pattern)是一种结构型设计模式,它用于将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。适配器模式特别有用在你想复用一些现有的类,但它们的接口不符合你的需求时。

  • 接口转换:适配器模式的核心是接口转换,它通过引入一个适配器类,把现有类的接口转化为客户所期望的接口。
  • 类适配器与对象适配器
    • 类适配器:使用继承来实现适配器功能。
    • 对象适配器:使用组合来实现适配器功能,更加灵活,因为它不依赖于具体的实现而是依赖于接口。

下面是一个适配器模式的示例代码

1
2
3
4
// 目标接口 - 电源插座
interface PowerSocket {
void plugIn();
}
1
2
3
4
5
6
// 需要适配的旧插头
class OldPlug {
void connect() {
System.out.println("Old plug connected.");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// 适配器 - 将旧插头适配到电源插座接口
class PlugAdapter implements PowerSocket {
private OldPlug oldPlug;

public PlugAdapter(OldPlug oldPlug) {
this.oldPlug = oldPlug;
}

@Override
public void plugIn() {
oldPlug.connect();
}
}
1
2
3
4
5
6
7
8
// 客户端代码
public class AdapterPatternExample {
public static void main(String[] args) {
OldPlug oldPlug = new OldPlug(); // 创建一个旧插头
PowerSocket adapter = new PlugAdapter(oldPlug); // 创建适配器
adapter.plugIn(); // 使用适配器插入旧插头
}
}

UML

AdaptorUML

代理模式

代理模式简而言之就是在不改变原始接口的前提下,使用另一个接口对原始接口的功能进行扩展。

下面是一个代理模式的示例代码

1
2
3
4
// 原始接口
public interface Browser {
void request();
}
1
2
3
4
5
6
7
// 接口实现类
public class BrowserImpl implements Browser {
@Override
public void request() {
System.out.println("Sending Request....");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 代理类
public class Proxy implements Browser {
private final Browser browser;

public Proxy(BrowserImpl browser) {
this.browser = browser;
}

@Override
public void request() {
System.out.println("Proxy handling request....");
browser.request();
}
}
1
2
3
4
5
6
7
8
// 客户端代码
public class Client {
public static void main(String[] args) {
BrowserImpl browser = new BrowserImpl();
Proxy proxy = new Proxy(browser);
proxy.request();
}
}
1
2
3
Output:
Proxy handling request....
Sending Request....

UML

ProxyUML