原型模式
这篇文章聊聊原型模式,官方给的定义如下:
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
有没有这样一种感觉?写的都是中文自己也认识,但是组合在一起完全不知道说的是什么意思。其实简单的说就是“克隆”
它的适用场景如下
当一个系统应该独立于它的产品创建、构成和表示时。
当要实例化的类是在运行时刻指定时,例如,通过动态装载。
为了避免创建一个与产品类层次平行的工厂类层次时。
当一个类的实例只能有几个不同状态组合中的一种时。
建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
很明显适用场景是我从文档上复制的
# 举个例子
其实这种设计模式我们每天都在用,当然可能不是写代码用。我在窗体上创建一个按钮,并对这个按钮复制粘贴多次,于是就有了下图的样子。
那么我的问题是你复制的是按钮的什么东西?其实我们是通过复制粘贴的动作完成了对现有按钮的克隆操作。而克隆的是按钮的整个对象
有朋友可能会提出疑问,这个复制粘贴也不需要我们来写啊。这不是已经有了嘛。好,那么接着往下看
# 提个需求
学校要给学生颁发”三好学生“的奖状,现在需要设计一下代码该如何实现这一操作
简单分析下
同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,可以使用原型模式复制多个“三好学生”奖状出来,然后在修改奖状上的名字即可
其实这就是原型模式的一个应用场景。比较尴尬的是 Delphi 不想其他编程语言提供了对象的克隆功能(比如:Java 有Object.clone方法),所以在 Delphi 中实现对象的克隆功能需要自己编写代码
万幸的是VCL的体系结构中的 TPersistent 类有一个 Assign 方法(这是一个过程),该方法叫常用于两个对象属性的复制。其代码如下,所在的单元 System.Classes
procedure TPersistent.Assign(Source: TPersistent);
begin
if Source <> nil then Source.AssignTo(Self) else AssignError(nil);
end;
2
3
4
在官方文档中有这么一段描述
The Assign method of TPersistent calls AssignTo if the descendant object does not succeed in copying the properties of a source object. The AssignTo method defined by TPersistent raises an EConvertError exception.
译文:如果Descendant对象未成功复制源对象的属性,则TPersistent调用的分配方法。 由TPersistent定义的分配方法引发了一个异常异常。
其实没有看太懂,只是看明白了会报异常。但是在”Delphi模式编程“一书上看到一段说明,如果由 AssignedTo 方法来实现复制,那么必须保证源对象的类已经重写了 AssignedTo 方法,否则会抛出 AssignError 异常
# 代码实现
unit UnitPrototype;
interface
uses
System.Classes;
type
TPrototype = class(TPersistent)
protected
//自己实现克隆的函数
function Clone: TPrototype; virtual; abstract;
end;
TCitation = class(TPrototype)
private
FName: string;
public
property Name: string read FName write FName;
//重写父类的方法
procedure Assign(Source: TPersistent); override;
function Clone: TPrototype; override;
end;
implementation
{ TConcreatePrototype1 }
procedure TCitation.Assign(Source: TPersistent);
begin
//类型转换并完成属性赋值
if Source is TCitation then begin
with Source as TCitation do begin
self.Name := Name;
end;
end
else begin
inherited;
end;
end;
function TCitation.Clone: TPrototype;
begin
//此处的 Result 所代表的为 目标(target)
Result := TCitation.Create;
//将 源 复制到 目标并返回
Result.Assign(self);
end;
end.
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
调用
program Prototype;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
UnitPrototype in 'UnitPrototype.pas';
begin
var Citation := TCitation.Create();
Citation.Name := '小黑';
//Writeln(Integer(@Citation).ToHexString);
Writeln(Citation.Name+'同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!');
//克隆一个对象
var Citation1 := Citation.Clone();
//在没有重新赋值之前,克隆出来的对象保持原来的值
Writeln(Citation.Name);
Readln;
end.
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
# 结语
这篇文章是设计模式中创建型模式全部梳理完成了。又来新的授课任务了,不知道后面还能不能维持正常的文章更新。。。