設計模式

裝飾器模式

裝飾器模式(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