跟着老侯玩编程 跟着老侯玩编程
首页
  • 基础语法
  • 网络编程
  • 设计模式
  • 基础篇
  • 进阶篇
  • 框架篇
  • Redis
  • Alibaba
  • 课程目录
  • 码农宝典
留言
首页
  • 基础语法
  • 网络编程
  • 设计模式
  • 基础篇
  • 进阶篇
  • 框架篇
  • Redis
  • Alibaba
  • 课程目录
  • 码农宝典
留言
  • 基础语法

    • 单元文件
    • 变量和常量
    • 内联变量
    • 基本数据类型
    • 复合数据类型
    • 语句(选择语句)
    • 语句(循环语句)
    • 数组
    • 初识例程
    • 初识面向对象
    • 属性Property
    • 面向对象的方法
    • 指针
    • 接口
    • 匿名函数和委托实现
    • 多态
    • 字符串详解
    • 异常处理
    • 反射机制
    • 泛型容器
    • JSON
    • 文件操作
    • Dll创建并调用
    • DLL初始化和退出处理
    • Package
    • 理解消息循环
    • VCL与Windows消息
    • 钩子原理
    • 进程通讯-内存映像
    • 多线程开篇
    • 线程控制
    • 线程同步
  • 网络编程

    • 网络编程基础
    • Delphi网络编程
    • select
    • WSAAsyncSelect
    • WSAEventSelect
  • 设计模式

    • 单例模式
    • 单例模式二
    • 策略模式
    • 简单工厂模式
    • 建造者模式
    • 原型模式
    • 模板方法模式
    • 状态模式
    • 迭代器模式
    • 解释器模式
    • 责任链模式
    • 中介者模式
    • 备忘录模式
    • 命令模式
    • 观察者模式
    • 访问者模式
    • 适配器模式
    • 桥接模式
      • 实战案例
      • 代码实现
      • 结语
  • Delphi
  • 设计模式
舞动的代码
2022-04-29
目录

桥接模式

桥接模式是软件设计模式中最复杂的模式之一,它把事物对象和其具体行为、具体特征分离开来,使它们可以各自独立的变化。事物对象仅是一个抽象的概念。如"圆形"、"三角形"归于抽象的"形状"之下,而"画圆"、"画三角"归于实现行为的"画图"类之下,然后由"形状"调用"画图"。

引自维基百科

按照维基百科的描述,绘制UML如下

UML图解析

抽象类和接口是聚合的关系,即调用和被调用的关系。如此一来搭好桥后,具体实现类调用方法=>父类抽象类的方法=>行为接口方法=>具体接口行为实现类,以完成连接,同时两者又相互独立易扩展:

从上图可以很明显的看到Shape类就相当于桥,通过它让接口和本身子类产生了关联

优点

  • 分离抽象接口及其实现部分,使得抽象和实现可以沿着各自的维度来变化

  • 桥接模式有时类似于多继承方案。但是多继承方案违背了类的单一职责原则,复用性比较差,而且多继承结构中累的个数非常庞

  • 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原系统

缺点:

桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

# 实战案例

需求:现在有3个英雄,每个英雄可以任意搭配2种种召唤师技能

常见的解法:每个英雄都配备2种召唤师技能,如果需要增加英雄,每增加一个英雄类相应增加2个召唤师技能类,如果需要增加技能,需要修改每一个英雄类和在技能族中添加新技能。很明显不应该使用这种方式,一旦增加技能那将是地狱级难度

桥接模式:技能和英雄是互相独立变化的两个维度,通过关联方式产生联系,无论英雄类还是召唤师技能类增加都不会互相影响

类图如下

# 代码实现

客户端调用代码

program BridgePattern;

{$APPTYPE CONSOLE}

{$R *.res}

 {桥接模式}
uses
  System.SysUtils,
  BridgeUnit in 'BridgeUnit.pas';

var
  List: TSkill;

begin
  try

    //构造英雄
    var SindlaHero := TSindlaHero.Create();

    //创建技能列表,相当于装配技能
    List[0] := TFastRun.create();
    List[1] := TLgnition.Create();
    SindlaHero.SkillList := List;

    //辛德拉使用技能-引燃
    SindlaHero.UseSkill(Lgnition);

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  readln;
end.

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

核心单元

unit BridgeUnit;

interface

type
  ISkill = interface
  //技能接口
    ['{70A22670-D265-4CE2-9367-881BBA434D3A}']
    //技能功效,可以作为技能的具体实现方式
    procedure skillEffect(HeroName: string);
  end;

  TFastRun = class(TInterfacedObject, ISkill)
  //疾跑
  public
    procedure skillEffect(HeroName: string); overload;
  end;

  TLgnition = class(TInterfacedObject, ISkill)
  //引燃
  public
    procedure skillEffect(HeroName: string); overload;
  end;

type
    //技能列表
  TSkill = array[0..1] of ISkill;
  //技能选项

  TSkillEnum = (Lgnition, FastRun);

  THero = class abstract

  //英雄类
  private
    FSkillList: TSkill;
  public
    property SkillList: TSkill read FSkillList write FSkillList;
    procedure UseSkill(SkillEnum: TSkillEnum); virtual; abstract;
  end;

  TGoldenHero = class(THero)
  //金克丝
  public
    procedure UseSkill(SkillEnum: TSkillEnum); override;
  end;

  TSindlaHero = class(THero)
  //辛德拉
  public
    procedure UseSkill(SkillEnum: TSkillEnum); override;
  end;

implementation

{ TFastRun }

procedure TFastRun.skillEffect(HeroName: string);
begin
  Writeln('召唤师【' + HeroName + '】开启疾跑,移速增加300%');
end;

{ TLgnition }

procedure TLgnition.skillEffect(HeroName: string);
begin
  Writeln('召唤师【' + HeroName + '】开启引燃,对目标增加10%的持续伤害,持续时间6秒');
end;

{ TGoldenHero }

procedure TGoldenHero.UseSkill(SkillEnum: TSkillEnum);
begin

  case SkillEnum of
    Lgnition:
      begin
        SkillList[0].skillEffect('金克丝');
      end;
    FastRun:
      begin
        SkillList[1].skillEffect('金克丝');
      end;

  end;

end;

{ TSindlaHero }

procedure TSindlaHero.UseSkill(SkillEnum: TSkillEnum);
begin
  case SkillEnum of
    Lgnition:
      begin
        SkillList[0].skillEffect('辛德拉');
      end;
    FastRun:
      begin
        SkillList[1].skillEffect('辛德拉');
      end;

  end;
end;

end.

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

运行结果

# 结语

第一次尝试使用Delphi中的枚举类型,各位不要笑话。还有英雄联盟中的英雄人物的英文名实在不知道怎么写,用翻译软件直接翻译的。。。

适配器模式

← 适配器模式

Theme by Vdoing | Copyright © 2013-2023 冀ICP备16006233号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×