设计模式之美:Prototype(原型)

news/2024/7/19 11:16:49 标签: 设计模式, 爬虫

索引

  • 别名
  • 意图
  • 结构
  • 参与者
  • 适用性
  • 缺点
  • 效果
  • 相关模式
  • 命名约定
  • 实现
    • 实现方式(一):使用一个原型管理器。
    • 实现方式(二):使用浅拷贝实现克隆(Clone)操作。
    • 实现方式(三):使用深拷贝实现克隆(Clone)操作。
    • 实现方式(四):初始化克隆对象。

别名

  • Clone

意图

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

结构

参与者

Prototype

  • 声明一个克隆自身的接口。

ConcretePrototype

  • 实现一个克隆自身的操作。

Client

  • 让一个原型克隆自身从而创建一个新的对象。

适用性

在以下情况下可以使用 Prototype 模式:

  • 一个系统要独立于它的产品的创建、构成和表示时。
  • 当要实例化的类是在运行时刻指定时,例如:通过动态装载。
  • 为了避免创建一个与产品类层次平行的工厂类层次时。
  • 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

缺点

  • 每一个 Prototype 子类都必须实现 Clone 操作。当内部包括一些不支持拷贝或有循环引用的对象时,实现克隆可能也会很困难。

效果

  • 它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目。
  • 使客户无需改变即可使用与特定应用相关的类。
  • 运行时刻增加和删除产品。
  • 改变值以指定新对象。
  • 改变结构以指定新对象。
  • 减少子类的构造。
  • 用类动态配置应用。

相关模式

  • Abstract Factory 可以用 Prototype 来实现。
  • Composite 和 Decorator 模式的设计也可以从 Prototype 获益。

命名约定

使用命名约定是一个好习惯,例如,总是声明那些实现克隆的操作为 Clone()。

实现

实现方式(一):使用一个原型管理器。

当一个系统中原型数目不固定时,可以保持一个可用原型的注册表,用以存储和检索原型。我们称这个注册表为原型管理器(Prototype Manager)。

客户在克隆一个原型前会先向注册表请求该原型。

 1 namespace PrototypePattern.Implementation1
 2 {
 3   public abstract class AbstractOrInterfaceOfPrototypeProduct
 4   {
 5     public int ValueProperty1 { get; set; }
 6 
 7     public abstract AbstractOrInterfaceOfPrototypeProduct Clone();
 8   }
 9 
10   public class ConcretePrototypeProductA : AbstractOrInterfaceOfPrototypeProduct
11   {
12     public override AbstractOrInterfaceOfPrototypeProduct Clone()
13     {
14       return new ConcretePrototypeProductA()
15       {
16         ValueProperty1 = this.ValueProperty1,
17       };
18     }
19   }
20 
21   public class ConcretePrototypeProductB : AbstractOrInterfaceOfPrototypeProduct
22   {
23     public override AbstractOrInterfaceOfPrototypeProduct Clone()
24     {
25       return new ConcretePrototypeProductB()
26       {
27         ValueProperty1 = this.ValueProperty1,
28       };
29     }
30   }
31 
32   public class ProductPrototypeManager
33   {
34     private Dictionary<string, AbstractOrInterfaceOfPrototypeProduct> _registry
35       = new Dictionary<string, AbstractOrInterfaceOfPrototypeProduct>();
36 
37     public void Register(string name,
38       AbstractOrInterfaceOfPrototypeProduct prototypeProduct)
39     {
40       _registry[name] = prototypeProduct;
41     }
42 
43     public void Unregister(string name)
44     {
45       _registry.Remove(name);
46     }
47 
48     public AbstractOrInterfaceOfPrototypeProduct Retrieve(string name)
49     {
50       return _registry[name];
51     }
52 
53     public bool IsRegisterd(string name)
54     {
55       return _registry.ContainsKey(name);
56     }
57   }
58 
59   public class Client
60   {
61     public void TestCase1()
62     {
63       AbstractOrInterfaceOfPrototypeProduct prototypeProduct1 = new ConcretePrototypeProductA();
64       AbstractOrInterfaceOfPrototypeProduct prototypeProduct2 = new ConcretePrototypeProductB();
65 
66       ProductPrototypeManager manager = new ProductPrototypeManager();
67       manager.Register("PrototypeProduct1", prototypeProduct1);
68       manager.Register("PrototypeProduct2", prototypeProduct2);
69 
70       AbstractOrInterfaceOfPrototypeProduct clonedProduct1 = manager.Retrieve("PrototypeProduct1").Clone();
71 
72       if (manager.IsRegisterd("PrototypeProduct2"))
73       {
74         AbstractOrInterfaceOfPrototypeProduct clonedProduct2 = manager.Retrieve("PrototypeProduct2").Clone();
75       }
76     }
77   }
78 }

实现方式(二):使用浅拷贝实现克隆(Clone)操作。

Prototype 模式最困难的部分在于正确的实现 Clone 操作。

浅拷贝(Shallow Copy)在拷贝时只复制对象所有字段的值。如果字段是值类型,则复制其值;如果字段是引用类型,则复制引用指针。

 1 namespace PrototypePattern.Implementation2
 2 {
 3   public class ReferencedClass
 4   {
 5     public int ReferencedClassProperty1 { get; set; }
 6   }
 7 
 8   public abstract class AbstractOrInterfaceOfPrototypeProduct
 9   {
10     public int ValueProperty1 { get; set; }
11     public ReferencedClass ReferenceProperty2 { get; set; }
12 
13     public abstract AbstractOrInterfaceOfPrototypeProduct Clone();
14   }
15 
16   public class ConcreteShallowCopyPrototypeProductA
17     : AbstractOrInterfaceOfPrototypeProduct
18   {
19     public ConcreteShallowCopyPrototypeProductA()
20     {
21       this.ReferenceProperty2 = new ReferencedClass()
22       {
23         ReferencedClassProperty1 = 111
24       };
25     }
26 
27     public override AbstractOrInterfaceOfPrototypeProduct Clone()
28     {
29       return new ConcreteShallowCopyPrototypeProductA()
30       {
31         ValueProperty1 = this.ValueProperty1,
32         ReferenceProperty2 = this.ReferenceProperty2,
33       };
34     }
35   }
36 
37   public class Client
38   {
39     public void TestCase2()
40     {
41       AbstractOrInterfaceOfPrototypeProduct prototypeProduct1 = new ConcreteShallowCopyPrototypeProductA();
42       AbstractOrInterfaceOfPrototypeProduct clonedProduct1 = prototypeProduct1.Clone();
43       bool areEqual1 = object.ReferenceEquals(
44         prototypeProduct1.ReferenceProperty2, 
45         clonedProduct1.ReferenceProperty2);
46     }
47   }
48 }

实现方式(三):使用深拷贝实现克隆(Clone)操作。

深拷贝(Deep Copy)涉及对源对象整个结构的拷贝。

深拷贝在拷贝时复制对象的所有字段的值。如果字段是值类型,则复制其值;如果字段是引用类型,则会将这个引用指针指向的对象也克隆一份。

可以通过序列化和反序列化来实现深拷贝。

 1 namespace PrototypePattern.Implementation3
 2 {
 3   public class ReferencedClass
 4   {
 5     public int ReferencedClassProperty1 { get; set; }
 6   }
 7 
 8   public abstract class AbstractOrInterfaceOfPrototypeProduct
 9   {
10     public int ValueProperty1 { get; set; }
11     public ReferencedClass ReferenceProperty2 { get; set; }
12 
13     public abstract AbstractOrInterfaceOfPrototypeProduct Clone();
14   }
15 
16   public class ConcreteShallowCopyPrototypeProductA
17     : AbstractOrInterfaceOfPrototypeProduct
18   {
19     public ConcreteShallowCopyPrototypeProductA()
20     {
21       this.ReferenceProperty2 = new ReferencedClass() 
22       { 
23         ReferencedClassProperty1 = 111 
24       };
25     }
26 
27     public override AbstractOrInterfaceOfPrototypeProduct Clone()
28     {
29       return new ConcreteShallowCopyPrototypeProductA()
30       {
31         ValueProperty1 = this.ValueProperty1,
32         ReferenceProperty2 = this.ReferenceProperty2,
33       };
34     }
35   }
36 
37   public class ConcreteDeepCopyPrototypeProductB
38     : AbstractOrInterfaceOfPrototypeProduct
39   {
40     public ConcreteDeepCopyPrototypeProductB()
41     {
42       this.ReferenceProperty2 = new ReferencedClass() 
43       { 
44         ReferencedClassProperty1 = 222 
45       };
46     }
47 
48     public override AbstractOrInterfaceOfPrototypeProduct Clone()
49     {
50       return new ConcreteDeepCopyPrototypeProductB()
51       {
52         ValueProperty1 = this.ValueProperty1,
53         ReferenceProperty2 = new ReferencedClass()
54         {
55           ReferencedClassProperty1 =
56             this.ReferenceProperty2.ReferencedClassProperty1
57         },
58       };
59     }
60   }
61 
62   public class Client
63   {
64     public void TestCase3()
65     {
66       AbstractOrInterfaceOfPrototypeProduct prototypeProduct1 = new ConcreteShallowCopyPrototypeProductA();
67       AbstractOrInterfaceOfPrototypeProduct clonedProduct1 = prototypeProduct1.Clone();
68       bool areEqual1 = object.ReferenceEquals(
69         prototypeProduct1.ReferenceProperty2,
70         clonedProduct1.ReferenceProperty2);
71 
72       AbstractOrInterfaceOfPrototypeProduct prototypeProduct2 = new ConcreteDeepCopyPrototypeProductB();
73       AbstractOrInterfaceOfPrototypeProduct clonedProduct2 = prototypeProduct2.Clone();
74       bool areEqual2 = object.ReferenceEquals(
75         prototypeProduct2.ReferenceProperty2,
76         clonedProduct2.ReferenceProperty2);
77 
78       Console.WriteLine("{0}, {1}", areEqual1, areEqual2);
79     }
80   }
81 }

实现方式(四):初始化克隆对象。

客户可能会希望使用一些值来初始化该对象的内部状态。

但在 Clone 操作中传递参数会破坏克隆接口的统一性。

原型的类可以在 Clone 操作之后,调用包含初始化参数的 Initialize 方法来设定对象内部状态。

 1 namespace PrototypePattern.Implementation4
 2 {
 3   public class ReferencedClass
 4   {
 5     public int ReferencedClassProperty1 { get; set; }
 6   }
 7 
 8   public abstract class AbstractOrInterfaceOfPrototypeProduct
 9   {
10     public int ValueProperty1 { get; set; }
11     public ReferencedClass ReferenceProperty2 { get; set; }
12 
13     public abstract AbstractOrInterfaceOfPrototypeProduct Clone();
14   }
15 
16   public class ConcreteDeepCopyPrototypeProductB
17     : AbstractOrInterfaceOfPrototypeProduct
18   {
19     public ConcreteDeepCopyPrototypeProductB()
20     {
21     }
22 
23     public void Initialize(int propertyValue)
24     {
25       this.ValueProperty1 = propertyValue;
26       this.ReferenceProperty2.ReferencedClassProperty1 = propertyValue;
27     }
28 
29     public override AbstractOrInterfaceOfPrototypeProduct Clone()
30     {
31       return new ConcreteDeepCopyPrototypeProductB()
32       {
33         ValueProperty1 = this.ValueProperty1,
34         ReferenceProperty2 = new ReferencedClass()
35         {
36           ReferencedClassProperty1 =
37             this.ReferenceProperty2.ReferencedClassProperty1
38         },
39       };
40     }
41   }
42 
43   public class Client
44   {
45     public void TestCase4()
46     {
47       AbstractOrInterfaceOfPrototypeProduct prototypeProduct2 = new ConcreteDeepCopyPrototypeProductB();
48       ConcreteDeepCopyPrototypeProductB clonedProduct2 = 
49         (ConcreteDeepCopyPrototypeProductB)prototypeProduct2.Clone();
50 
51       clonedProduct2.Initialize(123);
52     }
53   }
54 }

设计模式之美》为 Dennis Gao 发布于博客园的系列文章,任何未经作者本人同意的人为或爬虫转载均为耍流氓。


http://www.niftyadmin.cn/n/981162.html

相关文章

通过 Samba 服务实现 Linux 与 Windows 间文件共享

文章目录1. 简述 Samba 服务2. 配置 Samba 服务端3. 访问 Samba 服务端1. 简述 Samba 服务 从百度百科得到的说明&#xff1a;Samba 是在 Linux 和 UNIX 系统上实现 SMB 协议的一个免费软件&#xff0c;由服务器及客户端程序构成。SMB&#xff08;Server Messages Block&#x…

Oracle insert大量数据经验之谈(转)

在很多时候&#xff0c;我们会需要对一个表进行插入大量的数据&#xff0c;并且希望在尽可能短的时间内完成该工作&#xff0c;这里&#xff0c;和大家分享下我平时在做大量数据insert的一些经验。 前提&#xff1a;在做insert数据之前&#xff0c;如果是非生产环境&#xff0c…

SpringBoot Thymeleaf企业级真实应用:使用Flying Saucer结合iText5将HTML界面数据转换为PDF输出(四) 表格中断问题

接上一篇 SpringBoot Thymeleaf企业级真实应用&#xff1a;使用Flying Saucer结合iText5将HTML界面数据转换为PDF输出(三) 给pdf加水印、页眉页脚、页眉logo 设置表格的css样式 table {/*分页时表格换行, 可不用, 使用表格行换行即可*//*page-break-before: always;*/border-…

关于 Linux 系统中使用 cat 以及 vim 出现中文乱码问题的解决方法

文章目录前言1. 乱码表现2. 解决 cat 查看文件出现中文乱码3. 解决 vim 编辑文件出现中文乱码前言 前段时间在做 Samba 实验时遇到一个问题&#xff0c;即我在 Windows PC 端新建的 txt 文本&#xff0c;在 Linux 服务端去查看或者编辑时&#xff0c;会因为字符集的问题出现乱…

oracle dump event

一.Memory Dumps 1).Global Area ALTER SESSION SET EVENTS immediate trace name global_area level n; 1 包含PGA2 包含SGA4 包含UGA8 包含indrect memory 2).Library Cache ALTER SESSION SET EVENTS immediate trace name library_cache level n; 1 library cache统计信息2…

CentOS 7 删除 virbr0 设备

文章目录前言具体删除步骤前言 CentOS 7 若安装时带有虚拟化服务&#xff0c;那么一般会看到系统里面多出了一个 virbr0 的设备&#xff0c;并配有一个私网地址。在系统启用了 libvird.service 时&#xff0c;会生成这样一个被命名为 virbr0 的设备&#xff08;或者称之为网桥&…

Linux 服务器挂载移动硬盘进行数据拷贝

文章目录前言配置步骤前言 之前工作的时候曾需要将 Linux 服务器里某个大文件拷贝到移动硬盘里面给同事&#xff0c;一开始想着直接通过网络传输拷贝到硬盘&#xff0c;后来发现这样速度实在是太慢了&#xff0c;然后就想到通过 USB 直接把移动硬盘给挂载到服务器上去进行拷贝…

边缘检测(3)Sobel边缘算子

Sobel边缘算子的卷积和如图2.2所示,图像中的每个像素都用这两个核做卷积。这两个核分别对垂直边缘和水平边缘响应最大&#xff0c;两个卷积的最大值作为该点的输出位。运算结果是一幅边缘幅度图像。 Sobel算子认为邻域的像素对当前像素产生的影响不是等价的&#xff0c;所以距离…