0%

技术圈最近几年出现一个明显趋势:

  • 过去大家疯狂拆单体,上微服务。
  • 现在很多公司开始“服务合并”,回归单应用。

于是两派争论不断:

  • 微服务派:单体是落后架构。
  • 单体派:微服务是过度设计。

但如果用系统演化的视角看,会发现一个有意思的真相:

架构从来不是先进与否的问题,
而是是否匹配当前业务复杂度。

而历史上,秦与汉的更替,恰好是一次经典的架构演化样本。


一、秦:一个高度集中的“单应用系统”

秦始皇 建立的国家结构,本质上是:

强中心、强一致、低自治的单应用架构。

核心特征:

  • 地方无自治模块(郡县制)
  • 所有关键决策汇聚中央
  • 统一协议(文字、度量衡、法律)
  • 强一致性执行

在“统一六国”的阶段,这种架构极其高效。

就像一个创业公司:

  • 创始人拍板快
  • 组织链路短
  • 方向一致
  • 执行迅猛

问题不在统一阶段。

问题在统一之后。


二、秦二世而亡:架构能力 < 业务复杂度

秦统一后,系统复杂度急剧上升:

  • 地域扩大数倍
  • 民族结构多样化
  • 边疆军事压力长期存在
  • 经济形态差异巨大

这相当于:

1
2
3
系统规模 x10
业务场景 x10
治理复杂度 xN

但架构没有升级。

仍然是:

  • 单中心决策
  • 高压执行
  • 强一致模型
  • 无自治模块

当复杂度超过架构承载能力时,会发生三件事:

1️⃣ 核心节点过载

皇帝成为唯一核心实例。

信息流、决策流全部集中。

一旦核心判断失误,影响是全局性的。


2️⃣ 局部问题无法局部消化

在单应用里:

1
模块之间高度耦合

局部民变,很快变成系统级崩溃。

没有“自治单元”可以隔离问题。


3️⃣ 无容灾机制

秦二世 继位之后,

核心实例性能下降。

但系统没有:

  • 副本机制
  • 权力缓冲层
  • 自治结构

结果就是:

单点退化 = 全局崩溃

这不是简单的“暴政问题”。

这是:

架构能力无法支撑增长后的业务复杂度。

秦的失败,本质是:

1
2
业务规模快速扩张
架构模型停留在创业阶段

三、单应用的优势与边界

单应用(Monolith)本身并不落后。

它在以下阶段非常合适:

  • 0 → 1
  • 组织规模小
  • 业务领域简单
  • 决策链短

优点非常明显:

  • 部署简单
  • 运维成本低
  • 调试方便
  • 强一致性

但问题在于:

当业务领域复杂度激增时,单体系统很难划清边界。

长期演进后会出现:

  • 模块耦合
  • 发布风险扩大
  • 团队协作冲突
  • 变更牵一发而动全身

这正是很多中大型企业的真实困境。


四、秦 → 汉:一次系统重构

刘邦 建立汉朝后,没有完全复制秦的架构。

而是做了一次关键调整:

在单中心之上,引入“局部自治模块”。

汉初:

  • 分封诸侯王
  • 地方拥有一定自主权
  • 中央与地方形成博弈关系

这相当于:

1
单体系统 → 加入模块化结构

虽然产生“七国之乱”,

但系统并未崩溃。

因为:

局部问题,可以局部解决。

后来到 汉武帝 时,

又逐步收回过度自治,

形成:

1
中心 + 受控自治

这是一种演化后的混合架构。

既避免完全单体,
也避免完全分布式失控。

汉朝寿命远超秦,

不是因为“更仁慈”。

而是因为:

架构开始匹配复杂度。


五、为什么今天很多企业在“回归单应用”?

过去十年,

企业高速增长,

组织复杂度激增,

微服务成为自然选择。

微服务解决的是:

  • 领域拆分
  • 团队并行
  • 独立扩容
  • 快速迭代

但现在很多企业面临:

  • 业务增长放缓
  • 成本压力上升
  • 团队规模收缩

这时:

1
架构复杂度 > 当前业务复杂度

于是开始合并服务。

这不是倒退。

这是规模回调。


六、真正的核心变量

架构的选择,本质上取决于:

1
业务复杂度 × 组织规模
  • 小规模 + 低复杂度 → 单应用
  • 高规模 + 多领域 → 微服务
  • 收缩期 → 适度合并

错误不在于用哪种。

错误在于:

规模变化了,架构没变。

秦的错误是:规模爆炸,架构未升级。

有些公司现在的错误是:规模收缩,架构没降级。


七、最后的思考

单应用不是落后。

微服务不是先进。

真正的问题是:

你的架构,是否还匹配当前业务阶段?

秦的教训不是“不要集权”。

而是:

当系统规模指数级增长时,
创业阶段的架构必须演化。

否则,增长本身会成为压力源。

而汉朝给我们的启示是:

架构演化,比架构选择更重要。

系统不会因为选择单体或微服务而失败。

系统会因为:

在复杂度变化时,没有及时重构。

👇👇👇 扫码体验小程序 👇👇👇

ai-vibe-coding-2026210151912

👇👇👇 扫码关注公众号 👇👇👇

ai-vibe-coding-2026210151858

在使用docker的时候,难免会遇到当前主机不支持运行docker的情况,这时可以使用运程ssh的形式连接一个已经创建了docker的主机,本地正常使用docker命令

Docker Machine Generic驱动

首先说明一下 Docker Machine Generic驱动
它可以 创建一个machines通过SSH使用已经存在的虚拟机或是主机。

Example
创建一个machine的实例,需要指定–driver generic,主机的IP地址,DNS名和SSH私钥路径去连接它.

1
2
3
4
5
docker-machine create \
--driver generic \
--generic-ip-address=203.0.113.81 \
--generic-ssh-key ~/.ssh/id_rsa \
vm

除了上述的命令,你还可以使用的选项如下

1
2
3
4
5
6
Options
--generic-engine-port:Docker Daemon使用的端口(注意:这个标识在boot2docker中无效)
--generic-ip-address:必需字段,主机IP地址.
--generic-ssh-key:SSH user的私钥路径.
--generic-ssh-user:SSH连接使用的username.
--generic-ssh-port:SSH使用的端口.

之后 eval $(docker-machine env vm)
注意 这里 vm 是你设置的 docker machine 名字

执行一个 hello world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

Docker的安装是非常方便的,但是有一些细节还是要注意一下,下面打开博客了解更多内容吧。

阅读全文 »

分布式事务的背景

当系统架构使用非单体应用的时候,如采用 面向服务架构、徽服务架构的时候,会将项目拆分为不同的应用服务到单独的运行环境中,应用服务之间通讯使用的如wcf、http、rpc等等远程调用技术、每个服务中都有自己的数据库数据源和本地事务,服务之间互不影响,这种情况下就产生了分布式事务的问题。

CAP是什么

CAP定律是指在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。

注意

1、这里说的是在一个分布式系统中才会出现的问题,在单体应用中不会出现CAP三者不可兼得的问题。

2、关于权衡,不要以为在所有时候都只能选择两个特性。在不存在网络失败的情况下(分布式系统正常运行时的必要条件),C和A能够同时保证。只有当网络失败时,才会在C和A之间做出选择。

接下来我们具体来了解CAP具体是什么?

Consistency(一致性)

对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。换句话说,一致性是站在分布式系统的角度,对访问本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。

Availability(可用性)

任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是不出错。

Partition tolerance(分区容错性)

由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉。换句话说,分区容忍性是站在分布式系统的角度,对访问本系统的客户端的再一种承诺:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。

CAP的取舍权衡

C、A、P三个特性只能满足其中两个,那么取舍的策略共有3种:

  • CA没有P;如果没有P就是没有分区的意思,这咱情况下系统没有扩展性,无法部署节点、也就无法完成分布式设计的思想。
  • CP没有A;不要可用性的情况下,每个服务器之间保持强一致性而P(分区)之间的数据同步需要一定的时间,同步期间用户会有不好的体验,有很多系统使用的是CP的方案,如 Redis、HBase等
  • AP没有C;如果没有C一致性,系统可以高可用分区的情况下,P分区情况下节点之间,节点使用本地数据提供服务,这样的方案下数据在全局来看无法达到一致性。一般在抢购的场景下会出现这种情况,如看到库存还在,但是抢购下单的时候发现库存已经不在了。牺牲数据一致的用户体验,让系统整体可以运行,不会阻塞用户的购物流程。

一般的大型互联网应用采用多主机,集群化部署的方式。这种多节点的架构方式下,对于P的容错是分布式系统架构下一定要面对的问题,于是只能在C和A之间做取舍,但是有时对于一些对C强一致性要求极高的场景中,如银行转账可以在A和P之间取舍,如果出现网络故障,宁可停止服务。

具体可以根据实际的业务场景选择适合的架构设计。

参考:

分布式CAP定理,为什么不能同时满足三个特性?_cpa原则三个特性-CSDN博客

设计模式是软件开发中常用的解决方案,而设计模式的六大原则则是指导我们创建可维护、可扩展、可重用的高质量软件的基本准则。在本文中,我们将深入探讨这六大原则,并为每个原则提供具体的例子。

1. 单一职责原则(Single Responsibility Principle - SRP)

单一职责原则要求一个类应该只有一个引起变化的原因。这意味着一个类应该只负责一项职责。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
public class FileManager
{
public void SaveFile(string content)
{
// 保存文件的具体实现
}

public void ParseFile(string filePath)
{
// 解析文件的具体实现
}
}

在上述例子中,FileManager类分别负责保存文件和解析文件,遵循了单一职责原则。

2. 开放封闭原则(Open-Closed Principle - OCP)

开放封闭原则要求软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。即通过添加新的代码来扩展现有功能,而不是修改已有代码。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface IShape
{
void Draw();
}

public class Circle : IShape
{
public void Draw()
{
// 画圆的具体实现
}
}

public class Square : IShape
{
public void Draw()
{
// 画正方形的具体实现
}
}

在上述例子中,通过添加新的实现类(如Triangle),我们可以轻松扩展支持新的形状,而不需要修改IShape接口及其现有实现类。

3. 里氏替换原则(Liskov Substitution Principle - LSP)

里氏替换原则要求子类能够替换其父类而不影响程序的正确性。即如果一个类型是父类型,那么它应该能够被子类型替代。

例子:

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
public class Rectangle
{
protected int Width;
protected int Height;

public void SetWidth(int width)
{
Width = width;
}

public void SetHeight(int height)
{
Height = height;
}
}

public class Square : Rectangle
{
public override void SetWidth(int width)
{
Width = width;
Height = width;
}

public override void SetHeight(int height)
{
Width = height;
Height = height;
}
}

在上述例子中,Square类继承自Rectangle类,并重写了SetWidthSetHeight方法,保证了子类能够替换父类而不破坏程序的正确性。

4. 依赖倒置原则(Dependency Inversion Principle - DIP)

依赖倒置原则要求高层模块不应该依赖于低层模块,而是应该依赖于抽象。同时,抽象不应该依赖于细节,细节应该依赖于抽象。

例子:

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 interface IWriter
{
void Write(string message);
}

public class ConsoleWriter : IWriter
{
public void Write(string message)
{
Console.WriteLine("Writing to console: " + message);
}
}

public class MessageProcessor
{
private readonly IWriter _writer;

public MessageProcessor(IWriter writer)
{
_writer = writer;
}

public void ProcessMessage(string message)
{
// 处理消息的逻辑
_writer.Write(message);
}
}

在上述例子中,MessageProcessor高层模块依赖于抽象IWriter接口,而不直接依赖于具体的ConsoleWriter实现,符合依赖倒置原则。

5. 接口隔离原则(Interface Segregation Principle - ISP)

接口隔离原则要求一个类不应该强迫其它类实现它们用不到的方法。接口应该小而专一。

例子:

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
public interface IWorker
{
void Work();
void Eat();
}

public class Programmer : IWorker
{
public void Work()
{
// 程序员的工作
}

public void Eat()
{
// 程序员的吃饭
}
}

public class Janitor : IWorker
{
public void Work()
{
// 看门员的工作
}

public void Eat()
{
// 看门员的吃饭
}
}

在上述例子中,通过接口隔离原则,ProgrammerJanitor只需实现与自己相关的方法,避免了强迫实现不需要的方法。

6. 合成复用原则(Composite Reuse Principle - CRP)

合成复用原则要求尽量使用对象组合,而不是继承。通过组合现有的对象来实现新的功能,而不是通过继承现有的类。

例子:

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 Engine
{
public void Start()
{
// 引擎启动逻辑
}
}

public class Car
{
private readonly Engine _engine;

public Car(Engine engine)
{
_engine = engine;
}

public void Start()
{
_engine.Start();
// 其他汽车启动逻辑
}
}

在上述例子中,Car类通过组合Engine类来实现汽车的启动功能,而不是通过继承Engine类。

通过理解和遵循这六

大原则,开发人员可以更好地设计出灵活、可维护的软件系统。这些原则为面向对象设计提供了指导方针,有助于构建更加健壮和可扩展的应用程序。

状态模式 - 行为型模式的状态切换之旅

在软件设计中,状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变其行为。状态模式的核心思想是将对象的行为与其状态分离,使得在不同的状态下可以选择不同的行为。本文将深入讨论状态模式的概念、实现方式以及在实际应用中的使用场景。

状态模式的概念

状态模式(State Pattern)是一种行为型设计模式,其核心思想是允许一个对象在其内部状态改变时改变其行为。状态模式将对象的状态和行为分离,使得对象在不同的状态下可以选择不同的行为。状态模式主要包括三个角色:上下文(Context)、抽象状态(State)和具体状态(ConcreteState)。

状态模式的 UML 类图

classDiagram
    class Context {
        - state: State
        + Request(): void
        + SetState(state: State): void
    }

    class State {
        + Handle(context: Context): void
    }

    class ConcreteStateA
    class ConcreteStateB

    Context --> State
    State <|.. ConcreteStateA
    State <|.. ConcreteStateB

状态模式的实现方式

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
45
46
47
48
49
50
51
using System;

// 抽象状态类
public abstract class State
{
public abstract void Handle(Context context);
}

// 具体状态类 A
public class ConcreteStateA : State
{
public override void Handle(Context context)
{
Console.WriteLine("Handling with ConcreteStateA");
// 在具体状态类中可以改变上下文的状态
context.SetState(new ConcreteStateB());
}
}

// 具体状态类 B
public class ConcreteStateB : State
{
public override void Handle(Context context)
{
Console.WriteLine("Handling with ConcreteStateB");
// 在具体状态类中可以改变上下文的状态
context.SetState(new ConcreteStateA());
}
}

// 上下文类
public class Context
{
private State state;

public Context(State initialState)
{
this.state = initialState;
}

public void Request()
{
// 上下文类将请求委托给当前状态处理
state.Handle(this);
}

public void SetState(State newState)
{
this.state = newState;
}
}

状态模式的应用场景

状态模式适用于以下情况:

  1. 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为。
  2. 一个操作中含有大量的条件语句,并且这些条件语句的目的是根据对象的状态选择不同的行为。
  3. 一个对象需要根据内部状态来改变它的状态。

状态模式的优势

  1. 封装性好: 状态模式将一个对象的状态封装到不同的状态类中,使得每个状态类的实现都相对独立,便于维护和扩展。
  2. 可扩展性: 可以轻松地增加新的状态类,扩展系统的功能。
  3. 避免条件语句: 状态模式通过将不同的状态分离,避免了大量的条件语句,使得代码更加清晰。

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Program
{
static void Main()
{
// 创建上下文对象,初始状态为 ConcreteStateA
Context context = new Context(new ConcreteStateA());

// 发起请求,由 ConcreteStateA 处理
context.Request();

// 发起请求,由 ConcreteStateB 处理
context.Request();
}
}

总结

状态模式是一种行为型设计模式,通过将对象的状态和行为分离,使得对象在不同的状态下可以选择不同的行为。状态模式适用于一个对象的行为取决于其内部状态,并且需要在运行时根据状态改变行为的场景。在实际应用中,状态模式常用于处理有限状态机、状态切换等场景。

中介者模式 - 行为型模式的协调调停者

在软件设计中,中介者模式是一种行为型设计模式,它定义了一个中介者对象,该对象封装了一组对象之间的交互方式。中介者模式使得对象之间不直接相互通信,而是通过中介者对象进行协调,降低了对象之间的耦合性。本文将深入讨论中介者模式的概念、实现方式以及在实际应用中的使用场景。

中介者模式的概念

中介者模式(Mediator Pattern)是一种行为型设计模式,其核心思想是定义一个中介者对象,该对象封装了一组对象之间的交互方式。中介者模式使得对象之间不直接相互通信,而是通过中介者对象进行协调。这样的设计降低了对象之间的耦合性,使得系统更加灵活和易于维护。

中介者模式的 UML 类图

classDiagram
    class Mediator {
        + RegisterColleague(colleague: Colleague): void
        + SendMessage(colleague: Colleague, message: string): void
    }

    class Colleague {
        - mediator: Mediator
        + Send(message: string): void
        + Receive(message: string): void
    }

    class ConcreteMediator {
        - colleagues: List
        + RegisterColleague(colleague: Colleague): void
        + SendMessage(colleague: Colleague, message: string): void
    }

    class ConcreteColleagueA
    class ConcreteColleagueB

    Mediator <|.. ConcreteMediator
    Colleague <|.. ConcreteColleagueA
    Colleague <|.. ConcreteColleagueB

中介者模式的实现方式

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using System;
using System.Collections.Generic;

// 抽象中介者
public interface Mediator
{
void RegisterColleague(Colleague colleague);
void SendMessage(Colleague colleague, string message);
}

// 抽象同事类
public abstract class Colleague
{
protected Mediator mediator;

public Colleague(Mediator mediator)
{
this.mediator = mediator;
}

public abstract void Send(string message);
public abstract void Receive(string message);
}

// 具体中介者
public class ConcreteMediator : Mediator
{
private List<Colleague> colleagues;

public ConcreteMediator()
{
this.colleagues = new List<Colleague>();
}

public void RegisterColleague(Colleague colleague)
{
colleagues.Add(colleague);
}

public void SendMessage(Colleague colleague, string message)
{
foreach (var c in colleagues)
{
if (c != colleague)
{
c.Receive(message);
}
}
}
}

// 具体同事类A
public class ConcreteColleagueA : Colleague
{
public ConcreteColleagueA(Mediator mediator) : base(mediator) { }

public override void Send(string message)
{
Console.WriteLine("Colleague A sends message: " + message);
mediator.SendMessage(this, message);
}

public override void Receive(string message)
{
Console.WriteLine("Colleague A receives message: " + message);
}
}

// 具体同事类B
public class ConcreteColleagueB : Colleague
{
public ConcreteColleagueB(Mediator mediator) : base(mediator) { }

public override void Send(string message)
{
Console.WriteLine("Colleague B sends message: " + message);
mediator.SendMessage(this, message);
}

public override void Receive(string message)
{
Console.WriteLine("Colleague B receives message: " + message);
}
}

中介者模式的应用场景

中介者模式适用于以下情况:

  1. 一组对象之间存在复杂的交互关系,导致它们之间的通信结构复杂难以理解。
  2. 对象之间的交互行为需要随时变化,或者需要增加新的对象时。
  3. 系统中的对象由于通信关系过于紧密,导致它们之间的耦合性较高。

中介者模式的优势

  1. 降低耦合性: 中介者模式通过将对象之间的通信集中在中介者中,降低了对象之间的耦合性。
  2. 简化对象交互: 中介者模式将对象之间的交互方式封装在中介者中,使得对象之间的通信更加简单清晰。
  3. 易于扩展: 可以通过增加新的同事类和调整中介者的实现,轻松地扩展系统。

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Program
{
static void Main()
{
// 创建具体中介者对象
ConcreteMediator mediator = new ConcreteMediator();

// 创建具体同事类对象,并注册到中介者
ConcreteColleagueA colleagueA = new ConcreteColleagueA(mediator);
ConcreteColleagueB colleagueB = new ConcreteColleagueB(mediator);
mediator.RegisterColleague(colleagueA);
mediator.RegisterColleague(colleagueB);

// 同事类之间通过中介者进行通信
colleagueA.Send("Hello from Colleague A");
colleagueB.Send("Hi from Colleague B");
}
}

总结

中介者模式是一种行为型设计模式,通过定义一个中介者对象,封装了一组对象之间的交互方式,降低了对象之间的耦合性。中介者模式使得对象之间不直接相互通信,而是通过中介者对象进行协调。在实际应用中

职责链模式 - 行为型模式的责任传递者

在软件设计中,职责链模式是一种行为型设计模式,它通过一系列处理对象组成的链条,依次处理请求,直到找到合适的处理者。职责链模式可以有效地解耦发送者和接收者,并允许多个对象处理同一个请求。本文将深入讨论职责链模式的概念、实现方式以及在实际应用中的使用场景。

职责链模式的概念

职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,其核心思想是将处理对象组成一条链,依次处理请求,直到找到合适的处理者。每个处理对象都包含一个指向下一个处理对象的引用,形成一个处理链。请求从链的头部开始,沿着链条传递,直到有一个处理对象能够处理该请求。

职责链模式的 UML 类图

classDiagram
    class Handler {
        - successor: Handler
        + SetSuccessor(successor: Handler): void
        + HandleRequest(request: int): void
    }

    class ConcreteHandlerA {
        + HandleRequest(request: int): void
    }

    class ConcreteHandlerB {
        + HandleRequest(request: int): void
    }

    Handler <|-- ConcreteHandlerA
    Handler <|-- ConcreteHandlerB

职责链模式的实现方式

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
45
46
using System;

// 抽象处理者类
public abstract class Handler
{
protected Handler successor;

public void SetSuccessor(Handler successor)
{
this.successor = successor;
}

public abstract void HandleRequest(int request);
}

// 具体处理者A
public class ConcreteHandlerA : Handler
{
public override void HandleRequest(int request)
{
if (request >= 0 && request < 10)
{
Console.WriteLine($"Concrete Handler A handles request {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}

// 具体处理者B
public class ConcreteHandlerB : Handler
{
public override void HandleRequest(int request)
{
if (request >= 10 && request < 20)
{
Console.WriteLine($"Concrete Handler B handles request {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}

职责链模式的应用场景

职责链模式适用于以下情况:

  1. 多个对象可以处理同一个请求,但具体由哪个对象处理在运行时确定。
  2. 系统需要动态地指定处理一个请求的对象集合。
  3. 请求的发送者和接收者之间需要解耦,使得系统更灵活。

职责链模式的优势

  1. 解耦发送者和接收者: 职责链模式可以有效地解耦请求的发送者和接收者,每个处理者只关心自己的处理逻辑。
  2. 灵活性和可扩展性: 可以动态地调整链上处理对象的顺序或者增加新的处理对象,提高系统的灵活性和可扩展性。
  3. 单一职责原则: 每个具体处理者都只负责自己能够处理的请求,符合单一职责原则。

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Program
{
static void Main()
{
// 创建具体处理者对象
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();

// 设置处理链
handlerA.SetSuccessor(handlerB);

// 发送请求,实际上会从处理链的头部开始,依次尝试每个处理者
handlerA.HandleRequest(15);
}
}

总结

职责链模式是一种行为型设计模式,通过将处理对象组成一条链,依次处理请求,实现了请求的发送者和接收者的解耦。职责链模式在需要多个对象处理同一个请求,且具体处理对象在运行时确定的情景中有广泛的应用。在实际应用中,职责链模式需要注意设计链上处理对象的逻辑,以确保请求能够正确地被处理。

模板方法模式 - 行为型模式的骨架定义者

在软件设计中,模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,将算法中的一些步骤延迟到子类中实现。模板方法模式允许子类在不改变算法结构的情况下重新定义算法中的某些步骤。本文将深入讨论模板方法模式的概念、实现方式以及在实际应用中的使用场景。

模板方法模式的概念

模板方法模式(Template Method Pattern)是一种行为型设计模式,其核心思想是定义一个算法的骨架,将算法中的一些步骤延迟到子类中实现。模板方法模式在父类中定义算法的结构,而将具体步骤的实现交给子类。这样,子类可以在不改变算法结构的情况下重新定义算法的某些步骤。

模板方法模式的 UML 类图

classDiagram
    class AbstractClass {
        # PrimitiveOperation1(): void
        # PrimitiveOperation2(): void
        + TemplateMethod(): void
    }

    class ConcreteClass {
        + PrimitiveOperation1(): void
        + PrimitiveOperation2(): void
    }

    AbstractClass <|-- ConcreteClass

模板方法模式的实现方式

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
using System;

// 抽象类
public abstract class AbstractClass
{
// 模板方法定义了算法的骨架,将某些步骤的实现交给子类
public void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
}

// 原语操作1,延迟到子类实现
protected abstract void PrimitiveOperation1();

// 原语操作2,延迟到子类实现
protected abstract void PrimitiveOperation2();
}

// 具体类
public class ConcreteClass : AbstractClass
{
// 实现原语操作1
protected override void PrimitiveOperation1()
{
Console.WriteLine("ConcreteClass Primitive Operation 1");
}

// 实现原语操作2
protected override void PrimitiveOperation2()
{
Console.WriteLine("ConcreteClass Primitive Operation 2");
}
}

模板方法模式的应用场景

模板方法模式适用于以下情况:

  1. 多个子类有共同的算法骨架,但其中某些步骤的实现可能不同。
  2. 不想让子类改变算法的骨架,只允许改变某些具体步骤的实现。
  3. 重构时,将相同的代码抽取到父类中,形成模板方法,提高代码的复用性。

模板方法模式的优势

  1. 代码复用: 模板方法模式将相同的算法骨架封装在父类中,提高了代码的复用性。
  2. 封装变化: 模板方法模式允许子类在不改变算法结构的情况下重新定义某些步骤的实现,封装了变化。
  3. 简化子类: 子类不需要关心算法的结构,只需实现具体步骤,简化了子类的设计。

使用示例

1
2
3
4
5
6
7
8
9
10
11
class Program
{
static void Main()
{
// 创建具体类对象
ConcreteClass concreteClass = new ConcreteClass();

// 调用模板方法,实际上会执行具体类中定义的算法骨架
concreteClass.TemplateMethod();
}
}

总结

模板方法模式是一种行为型设计模式,通过定义一个算法的骨架,将算法中的一些步骤延迟到子类中实现。模板方法模式允许子类在不改变算法结构的情况下重新定义算法的某些步骤,提高了代码的复用性和灵活性。在实际应用中,模板方法模式常用于多个子类有共同的算法骨架,但其中某些步骤的实现可能不同的场景。