Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 54 additions & 8 deletions src/adapter-pattern/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,65 @@

这样一来,你的客户端代码就可以像对待 `PayPalService` 一样对待 `AlipayAdapter`,而无需知道背后复杂的转换逻辑。

## structure
## 结构

1. **目标 (Target)**: (`PaymentProcessor` 接口)
* 定义了客户端代码所使用的特定于领域的接口。

2. **客户端 (Client)**: (`processPayment` 函数)
* 与实现了 `Target` 接口的对象进行交互。

3. **被适配者 (Adaptee)**: (`AlipayService` 类)
```typescript
// src/adapter-pattern/target/payment-processor.ts
export interface PaymentProcessor {
pay(amount: number): void;
}
```

2. **被适配者 (Adaptee)**: (`AlipayService` 类)
* 一个现有的类,其接口与 `Target` 接口不兼容。我们无法修改这个类。

4. **适配器 (Adapter)**: (`AlipayAdapter` 类)
```typescript
// src/adapter-pattern/adaptee/alipay-service.ts
export class AlipayService {
public makePayment(user: string, amountInCents: number): void {
console.log(`User ${user} is paying ${amountInCents / 100} CNY via Alipay.`);
}
}
```

3. **适配器 (Adapter)**: (`AlipayAdapter` 类)
* 一个可以同时与 `Target` 和 `Adaptee` 交互的类。它实现了 `Target` 接口,并在内部包装了 `Adaptee` 的一个实例。适配器接收所有 `Target` 接口的调用,并将它们转换为 `Adaptee` 接口的调用。
```typescript
// src/adapter-pattern/adapter/alipay-adapter.ts
export class AlipayAdapter implements PaymentProcessor {
private readonly alipayService: AlipayService;

constructor(alipayService: AlipayService) {
this.alipayService = alipayService;
}

public pay(amount: number): void {
const currentUser = 'user_123';
const amountInCents = amount * 100;
// 将调用转换为被适配者的方法
this.alipayService.makePayment(currentUser, amountInCents);
}
}
```

4. **客户端 (Client)**: (`processPayment` 函数)
* 与实现了 `Target` 接口的对象进行交互,而不知道其具体实现。
```typescript
// src/adapter-pattern/index.ts
function processPayment(processor: PaymentProcessor, amount: number) {
console.log('Client: Processing a payment...');
processor.pay(amount);
}

// 客户端可以无缝地使用旧服务...
const payPalService = new PayPalService();
processPayment(payPalService, 150);

// ...也可以使用通过适配器包装的新服务。
const alipayAdapter = new AlipayAdapter(new AlipayService());
processPayment(alipayAdapter, 200);
```

## 优点

Expand Down
87 changes: 68 additions & 19 deletions src/command-pattern/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,79 @@

命令模式通过引入“命令”对象来解决这个问题。我们将每一个请求(如“开灯”)都封装成一个具体的命令类(如 `LightOnCommand`)。这个命令对象持有一个对真正执行操作的对象(“接收者”,如 `Light` 实例)的引用。

遥控器(调用者)只持有一个 `Command` 接口的引用。当一个按钮被按下时,遥控器只管调用这个命令对象的 `execute()` 方法,而完全不需要知道这个命令具体会做什么,也不需要知道接收者是谁。这样一来,我们就可以在不修改遥-控器代码的情况下,动态地给按钮分配任何新的命令,实现了完美的解耦。
遥控器(调用者)只持有一个 `Command` 接口的引用。当一个按钮被按下时,遥控器只管调用这个命令对象的 `execute()` 方法,而完全不需要知道这个命令具体会做什么,也不需要知道接收者是谁。这样一来,我们就可以在不修改遥控器代码的情况下,动态地给按钮分配任何新的命令,实现了完美的解耦。

## 结构

1. **命令 (Command)**: (`Command` 接口)
* 通常只声明一个执行方法,如 `execute()`。

2. **具体命令 (Concrete Command)**: (`LightOnCommand`, `GarageDoorOpenCommand` 等类)
* 实现了 `Command` 接口。
* 持有一个对“接收者”对象的引用。
* `execute()` 方法的实现会调用接收者对象的一个或多个方法来完成请求。

3. **调用者 (Invoker)**: (`SimpleRemoteControl` 类)
* 持有一个 `Command` 对象。
* 调用者不直接创建命令对象,而是通过客户端代码来设置。
* 调用者只负责在适当的时候调用命令的 `execute()` 方法。

4. **接收者 (Receiver)**: (`Light`, `GarageDoor` 类)
* 包含了真正的业务逻辑。它知道如何实施和执行一个请求。
* 任何类都可以作为一个接收者。

5. **客户端 (Client)**: (`index.ts` 中的 `runSmartHomeSimulation` 函数)
* 负责创建接收者、具体命令,并将命令与接收者关联起来。
* 最后,将配置好的命令对象设置给调用者。
```typescript
// src/command-pattern/command/command.ts
export interface Command {
execute(): void;
}
```

2. **接收者 (Receiver)**: (`Light`, `GarageDoor` 类)
* 包含了真正的业务逻辑。它知道如何实施和执行一个请求,但它并不知道命令的存在。
```typescript
// src/command-pattern/receiver/light.ts
export class Light {
public on(): void {
console.log("Light is On");
}
public off(): void {
console.log("Light is Off");
}
}
```

3. **具体命令 (Concrete Command)**: (`LightOnCommand` 等类)
* 实现了 `Command` 接口,并将一个接收者对象绑定于自身的动作之上。
* 当 `execute()` 被调用时,它会调用接收者的相应方法。
```typescript
// src/command-pattern/command/light-on-command.ts
export class LightOnCommand implements Command {
private light: Light; // A reference to the receiver

constructor(light: Light) {
this.light = light;
}

public execute(): void {
this.light.on(); // The command delegates the action to the receiver
}
}
```

4. **调用者 (Invoker)**: (`SimpleRemoteControl` 类)
* 持有一个 `Command` 对象,并让它在需要时执行。调用者不关心命令的具体实现。
```typescript
// src/command-pattern/invoker/simple-remote-control.ts
export class SimpleRemoteControl {
private slot: Command;

public setCommand(command: Command): void {
this.slot = command;
}

public buttonWasPressed(): void {
this.slot.execute(); // The invoker just calls execute()
}
}
```

5. **客户端 (Client)**: (`index.ts`)
* 负责创建接收者、具体命令,并将命令与接收者关联起来。最后,将配置好的命令对象设置给调用者。
```typescript
// src/command-pattern/index.ts
const remote = new SimpleRemoteControl();
const light = new Light("Living Room");
const lightOn = new LightOnCommand(light);

remote.setCommand(lightOn);
remote.buttonWasPressed(); // Outputs: "Living Room light is On"
```

## 优点

Expand Down
81 changes: 78 additions & 3 deletions src/compound-pattern/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,93 @@

* **适配器模式 (Adapter)**
* **角色**: 我们使用 `GooseAdapter` 将一个具有不兼容接口的 `Goose` 对象(它只会 `honk()`)适配成一个 `Quackable` 对象(它会 `quack()`)。这使得我们的系统可以无缝地处理鹅,就像处理鸭子一样。
```typescript
// src/compound-pattern/adapter/goose-adapter.ts
export class GooseAdapter implements Quackable {
private goose: Goose;
// ...
public quack(): void {
// 将 quack() 调用转换为 honk() 调用
this.goose.honk();
this.notifyObservers();
}
}
```

* **装饰器模式 (Decorator)**
* **角色**: 我们使用 `QuackCounter` 装饰器来包装任何 `Quackable` 对象。它在不改变被包装对象代码的情况下,为其增加了“叫声计数”的新功能。
```typescript
// src/compound-pattern/decorator/quack-counter.ts
export class QuackCounter implements Quackable {
private duck: Quackable; // 被包装的鸭子
private static numberOfQuacks: number = 0;

constructor(duck: Quackable) {
this.duck = duck;
}

public quack(): void {
this.duck.quack(); // 委托给被包装的鸭子
QuackCounter.numberOfQuacks++; // 增加新功能
}
// ...
}
```

* **工厂模式 (Factory)**
* **角色**: 我们使用 `AbstractDuckFactory` 和两个具体的工厂(`DuckFactory` 和 `CountingDuckFactory`)来封装对象的创建过程。客户端代码通过工厂来获取鸭子实例,而无需关心这些鸭子是否被装饰过。这使得我们可以轻松地切换是否需要计数功能。
* **角色**: 我们使用 `AbstractDuckFactory` 和 `CountingDuckFactory` 来封装对象的创建过程。客户端通过工厂获取鸭子,而无需关心这些鸭子是否被装饰过。
```typescript
// src/compound-pattern/factory/counting-duck-factory.ts
export class CountingDuckFactory extends AbstractDuckFactory {
public createMallardDuck(): Quackable {
// 工厂负责用装饰器包装对象
return new QuackCounter(new MallardDuck());
}
// ...
}
```

* **组合模式 (Composite)**
* **角色**: 我们使用 `Flock` 类来将一群 `Quackable` 对象组合成一个单一的 `Quackable`。这使得客户端可以像对待一只鸭子一样,对待一整群鸭子(甚至是一个包含了其他鸭群的鸭群),极大地简化了客户端代码。
* **角色**: 我们使用 `Flock` 类来将一群 `Quackable` 对象组合成一个单一的 `Quackable`。这使得客户端可以像对待一只鸭子一样,对待一整群鸭子。
```typescript
// src/compound-pattern/composite/flock.ts
export class Flock implements Quackable {
private quackers: Quackable[] = [];

public add(quacker: Quackable): void {
this.quackers.push(quacker);
}

public quack(): void {
// 遍历并委托给每一个子组件
for (const quacker of this.quackers) {
quacker.quack();
}
}
// ...
}
```

* **观察者模式 (Observer)**
* **角色**: 我们让所有的 `Quackable` 对象都成为“可被观察的”(`QuackObservable`)。一个 `Quackologist`(观察者)可以注册到任何 `Quackable` 对象上。当鸭子叫的时候,它会通知观察者,让观察者知道是谁叫了。
* **角色**: 我们让所有的 `Quackable` 对象都成为“可被观察的”。一个 `Quackologist`(观察者)可以注册到任何 `Quackable` 对象上。当鸭子叫的时候,它会通知观察者。
```typescript
// src/compound-pattern/duck/mallard-duck.ts
export class MallardDuck implements Quackable {
// ...
public quack(): void {
console.log("Quack");
this.notifyObservers(); // 通知观察者
}
// ...
}

// src/compound-pattern/observer/quackologist.ts
export class Quackologist implements Observer {
public update(duck: QuackObservable): void {
console.log(`Quackologist: ${duck.constructor.name} just quacked.`);
}
}
```

这些模式共同协作,形成了一个优雅且强大的解决方案。

Expand Down
81 changes: 76 additions & 5 deletions src/decorator-pattern/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,86 @@

1. **组件 (Component)**: (`Beverage` 抽象类)
* 定义了被装饰的原始对象和装饰器共有的接口。
```typescript
// src/decorator-pattern/Component/Beverage.ts
export abstract class Beverage {
protected description: string = 'Unknown Beverage';

public getDescription(): string {
return this.description;
}

public abstract cost(): number;
}
```

2. **具体组件 (Concrete Component)**: (`Espresso` 类)
* 实现了组件接口,是被装饰的原始对象。可以有多个。
* 实现了组件接口,是被装饰的原始对象。
```typescript
// src/decorator-pattern/Component/Espresso.ts
export class Espresso extends Beverage {
constructor() {
super();
this.description = "Espresso";
}

public cost(): number {
return 1.99;
}
}
```

3. **装饰器 (Decorator)**: (`CondimentDecorator` 抽象类)
* 同样实现了组件接口,并持有一个对组件对象的引用(通过 `has-a` 关系)。它将所有请求都转发给被包装的组件。其主要目的是为所有具体的装饰器定义一个统一的接口。

4. **具体装饰器 (Concrete Decorator)**: (`Milk`, `Whip`, `Mocha` 类)
* 实现了装饰器,并为组件动态添加了新的行为或状态。它们在调用父类方法(即转发请求)之前或之后,执行自己额外的逻辑(如增加成本、添加描述)。
* 同样实现了组件接口,并持有一个对组件对象的引用(通过 `has-a` 关系)。
```typescript
// src/decorator-pattern/Decorator/CondimentDecorator.ts
export abstract class CondimentDecorator extends Beverage {
// This is the object we are decorating
protected beverage: Beverage;

// We need to reimplement getDescription() in the decorator
public abstract getDescription(): string;
}
```

4. **具体装饰器 (Concrete Decorator)**: (`Milk`, `Whip` 等类)
* 为组件动态添加了新的行为或状态。它们在调用父类方法(即转发请求)之前或之后,执行自己额外的逻辑。
```typescript
// src/decorator-pattern/Decorator/Milk.ts
export class Milk extends CondimentDecorator {
constructor(beverage: Beverage) {
super();
this.beverage = beverage;
}

public getDescription(): string {
// Add "Milk" to the description of the beverage we're decorating
return this.beverage.getDescription() + ', Milk';
}

public cost(): number {
// Add the cost of milk to the cost of the beverage
return .10 + this.beverage.cost();
}
}
```
5. **客户端 (Client)**: (`index.ts`)
* 客户端代码通过层层包装来动态地构建对象。
```typescript
// src/decorator-pattern/index.ts
// Start with a plain Espresso
let espresso: Beverage = new Espresso();

// Wrap it with Milk
espresso = new Milk(espresso);

// Wrap it with Whip
espresso = new Whip(espresso);

// Get the final description and cost
console.log(espresso.getDescription() + ' $' + espresso.cost());
// Outputs: Espresso, Milk, Whip $2.29
```

## 优点

Expand Down
Loading