设计模式-创建型-原型模式

引言:

  原型模式是什么?它是在什么场景下被提出的呢?本章节,我们将详细了解下原型模式。

  在软件系统中,当创建一个类的实例过程过于昂贵或复杂,并且我们需要创建多个这样类的实例时,如果我们通过new来创建类实例,这就会增加创建类的复杂度和创建过程与客户代码复杂的耦合度。如果采用工厂模式来创建这样的实例对象的话,随着产品类的不断增加,导致子类的数量不断增多,也导致了相应工厂类的增加,维护的代码维度增加了,因为有产品和工厂两个维度了,反而增加了系统复杂程度,所以在这里使用工厂模式来封装类创建过程并不合适。由于每个类实例都是相同的(类型相同),但是每个实例的状态参数会有不同,如果状态数值也相同就没意义了,有一个这样的对象就可以了。当我们需要多个相同的类实例时,可以通过对原来对象拷贝一份来完成创建,这个思路正是原型模式的实现方式。

定义:

  原型模式就是通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个对象的方法来创建更多的同类型对象。

原型模式的两种类型:

  object类的clone方法只会拷贝对象中基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

 1 internal class Program
 2 {
 3     private static void Main(string[] args)
 4     {
 5         SunWukong sunwukong = new SunWukong()
 6         {
 7             Id = 1,
 8             Name = "孙悟空",
 9             Weapon = new Weapon()
10             {
11                 Name = "如意金箍棒"
12             }
13         };
14         SunWukong xingzhesun = (SunWukong)sunwukong.Clone();
15         Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
16         Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
17         Console.WriteLine("===============================");
18
19         // 验证克隆后属性之间是否共享
20         xingzhesun.Id = 2;
21         xingzhesun.Name = "行者孙";
22         xingzhesun.Weapon.Name = "钉耙";
23         Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
24         Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
25         // 从结果可以看出,对于基本类型属性,克隆之后不共享,而对于对象来说是共享的,这就是浅拷贝
26         Console.WriteLine("===============================");
27         Console.WriteLine($"孙悟空的武器{sunwukong.Weapon.GetHashCode()},行者孙的武器{sunwukong.Weapon.GetHashCode()}");
28         // 打印hashcode值可以看出,克隆后的实例与原型的Weapon指向同一个地址
29     }
30 }
31
32 internal class SunWukong : ICloneable
33 {
34     public int Id { get; set; }
35     public string Name { get; set; }
36     public Weapon Weapon { get; set; }
37
38     public object Clone()
39     {
40         return this.MemberwiseClone();
41     }
42 }
43
44 internal class Weapon
45 {
46     public string Name { get; set; }
47 }

view code

  .net中提供了原型,即System命名空间下的接口ICloneable,只要实现该接口的Clone方法就可以之间原型拷贝。上述代码中遗留了一个问题,如何实现深拷贝问题。

 1 internal class Program
 2 {
 3     private static void Main(string[] args)
 4     {
 5         SunWukong sunwukong = new SunWukong()
 6         {
 7             Id = 1,
 8             Name = "孙悟空",
 9             Weapon = new Weapon()
10             {
11                 Name = "如意金箍棒"
12             }
13         };
14         SunWukong xingzhesun = (SunWukong)sunwukong.Clone();
15         // 引用类型再进行拷贝
16         xingzhesun.Weapon = (Weapon)xingzhesun.Weapon.Clone();
17         Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
18         Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
19         Console.WriteLine("===============================");
20         xingzhesun.Id = 2;
21         xingzhesun.Name = "行者孙";
22         xingzhesun.Weapon.Name = "钉耙";
23         Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
24         Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
25         Console.WriteLine("===============================");
26         Console.WriteLine($"孙悟空的武器{sunwukong.Weapon.GetHashCode()},行者孙的武器{xingzhesun.Weapon.GetHashCode()}");
27     }
28 }
29
30 internal class SunWukong : ICloneable
31 {
32     public int Id { get; set; }
33     public string Name { get; set; }
34     public Weapon Weapon { get; set; }
35
36     public object Clone()
37     {
38         return this.MemberwiseClone();
39     }
40 }
41
42 internal class Weapon : ICloneable
43 {
44     public string Name { get; set; }
45
46     public object Clone()
47     {
48         return this.MemberwiseClone();
49     }
50 }

view code

深拷贝:

  1、复制对象的基本数据类型的成员变量值。

  2、为所有引用类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝。

  3、深拷贝实现方式1:重写clone方法。

  4、深拷贝实现方式2:通过对象序列化。

原型模式的注意事项和细节:

  1、创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率。

  2、不用重新初始化对象,而是动态地获取对象运行时的状态。

  3、如果原始对象发生变化(增加或减少属性),其它克隆对象也会发生相应的变化,无需修改代码。

  4、在实现深克隆的时候可能需要比较复杂的代码。    

  5、使用原型模式复制不会调用类的构造方法。因为对象的复制是通过调用clone方法完成的,它直接在内存种复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。单例模式中,我们通过私有化构造函数来实现单例模式,但clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的。

原型模式的优点:

  1、原型模式向客户隐藏了创建新实例的复杂性。

  2、原型模式允许动态增加或较少产品类。

  3、原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。

  4、产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构。

缺点:

  1、需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改源码,即违反了OCP原则

参考:https://www.cnblogs.com/zhili/p/PrototypePattern.html

   https://yq.aliyun.com/articles/485574

原文地址:https://www.cnblogs.com/az4215/p/11525391.html

时间: 2024-10-10 06:27:37

设计模式-创建型-原型模式的相关文章

创建型—原型模式

1.原型模式意图: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.场景描述: 原型模式,利用实例自身的克隆功能来得到与原实例相同的新的实例. 设想西游记中的一个场景,唐僧师徒四人(白龙马除外),不过,该唐僧是个多事.喜欢使唤徒弟的唐僧.每当有事时,唐僧便会使唤他的三个徒弟去做.但是三个徒弟尽职尽责,为了保护师傅,必须留在唐僧身边.此时,多亏了三个徒弟能够千变万化,且都可通过毛发来变作自身(八戒.沙僧不知是否具有此功能?暂时看做有吧).当唐僧需要洗衣.化斋.喝水.探路.借宿

设计模式-创建型-工厂模式

工厂设计模式: 顾名思义,该模式是用来生产对象的.在面向对象的设计模式中,万物皆对象,若使用new来创建对象,就会对该对象产生强耦合,加入我们需要更换该对象,那么使用该对象的对象都需要进行修改,这显然违背了开闭原则(OCP).如果我们使用工厂来产生对象,我们只需要与这个工厂打交道就可以了,无需关心具体的对象,达到解耦的目的. 接下来我们从实际的案例出发,从无工厂到有工厂的区别. 去披萨店订购披萨,首先披萨的种类很多(CheesePizza.GreekPizza.DurianPizza{等),披萨

06.创建型————原型模式

package Create.e.Prototype; //原型业务类 需要实现克隆接口 public class Dog implements Cloneable{ public int legCounts; public Dog(int legCounts){ this.legCounts = legCounts; } public void changeLegCounts(){ this.legCounts *= 2; } public String toString(){ return

java设计模式--创建型模式

2016-04-24 10:10:34 创建型模式:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 注意:工厂模式可以分为三类: 1)简单工厂模式(Simple Factory) 2)工厂方法模式(Factory Method) 3)抽象工厂模式(Abstract Factory)  这三种模式从上到下逐步抽象,并且更具一般性.GOF在<设计模式>一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory).将简单工厂模式

JDK 源码 阅读 - 2 - 设计模式 - 创建型模式

A.创建型模式 抽象工厂(Abstract Factory) javax.xml.parsers.DocumentBuilderFactory DocumentBuilderFactory通过FactoryFinder实例化具体的Factory. 使用例子: DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docBuilder

设计模式——创建型模式

简单的说我们可以把23种设计模式可以归为三大类,分别是创建型模式.结构型模式和行为型模式. 今天,首先看一下创建型模式.创建型设计模式包括5种:单例模式(Singleton).工厂方法模式(Factory Method).抽象工厂模式(Abstract Factory).建造者模式(Builder).原型模式(Prototype).  1.单例模式(Singleton)        1)简介 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式是一种常用的软件设计模式.在它的核心结

C#设计模式-创建型模式(转)

一.简单工厂模式 简单工厂模式Simple Factory,又称静态工厂方法模式.它是类的创建模式.是由一个工厂对象决定创建出哪一种产品类的实例,是不同的工厂方法模式的一个特殊实现. 优点: u 模式的核心是工厂类,该类中含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅负责"消费"产品. u 简单工厂模式实现了对责任的分割. 缺点: u 当产品类有复杂的多层次等级结构时,工厂类只有它自己.以不变应万变. u 模式中工厂类集中了所

【C#设计模式——创建型模式】抽象工厂模式

抽象工厂模式比工厂模式具有更高层次的抽象性.当要返回一系列相关类中的某一个,而每个类都能根据需要返回不同的对象时,可以选择这种模式.直接进入示例. 示例描述:完成花园的规划,多种花园种类,每个里面多种植物 编写一个基类Garden,Garden就是抽象工厂.它定义了具体类中的方法,并返回一系列相关类中的某个类. public class Garden { protected Plant center, shade, border; protected bool showCenter, showS

【C#设计模式——创建型模式】工场方法模式

工场方法模式对简单工场模式进行了乔庙的扩展,不是用一个专门的类来决定实例化哪一个子类.相反,超类把这种决定延迟到每个子类.这种模式实际上没有决策点,就是没有直接选择一个子类实例化的决策. 看书上的例子有点复杂,自己写了一个简单例子: 示例目标:对数组进行定向排序 基类FormatList对指定数组进行排序,具体实现交给子类实现 public abstract class FormatList { public int[] result; protected abstract void Forma