设计模式(五)—— 原型模式

模式简介


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

通俗来说,原型模式就是从一个对象,通过复制的手段去创建另外一个对象,而且不需要知道任何创建的细节。

思考:这么做有什么好处?

  • 省略创建者类。例如在工厂方法中,客户端创建一个产品,必须调用相应工厂类中的方法获取产品实例。在原型模式中,原型本身提供Clone方法,因此原型的实例扮演了创建者和产品双重角色。
  • 减少创建实例带来的成本。这里所说的“成本”包括两个层面:系统性能的消耗创建实例的代码量。当初始化一个对象带来大量的性能消耗,需要创建多个实例且各个实例之间差别不大时,原型模式通过复制原型的方式减小系统性能的消耗。另一方面,当初始化对象需要大量繁杂的代码,使用原型模式避免了代码的重复。

结构说明


UML类图

角色说明

  • Prototype

抽象原型类。声明一个克隆自身的接口(抽象方法)

  • ConcretePrototype

具体原型类。实现一个克隆自身的方法

  • Client

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

示例分析


下面我们来看一个创建颜色Color对象的示例:

创建原型类Color(本示例省略了抽象原型类,改用ICloneable接口代替)

class Color : ICloneable
{
    private int red;
    private int green;
    private int yellow;
    public Color(int red,int green,int yellow)
    {
        this.red = red;
        this.green = green;
        this.yellow = yellow;
    }
    public object Clone()
    {
        Console.WriteLine($"Cloning color RGB: {red},{green},{yellow}");
        return this.MemberwiseClone() as Color;
    }
}

创建原型管理器ColorManager

class ColorManager
{
    Dictionary<string, Color> colors = new Dictionary<string, Color>();
    public Color this[string key]
    {
        get { return colors[key]; }
        set { colors.Add(key, value); }
    }

}

客户端向原型管理器注册,获取Color对象,以及动态注册原型

static void Main(string[] args)
{
    ColorManager colorManager = new ColorManager();

    //向原型管理器注册原型
    colorManager["red"] = new Color(255, 0, 0);
    colorManager["green"] = new Color(0, 255, 0);
    colorManager["yellow"] = new Color(0, 0, 255);

    //创建实例
    Color red = colorManager["red"].Clone() as Color;

    //动态注册原型
    Console.WriteLine("Start to register prototype : ");
    Console.WriteLine("Key : ");
    string key = Console.ReadLine();
    Console.WriteLine("RGB[example:255,54,0]:");
    string[] input = Console.ReadLine().Split(',');
    int[] rgb = Array.ConvertAll<string, int>(input, p => int.Parse(p));
    colorManager[key] = new Color(rgb[0], rgb[1], rgb[2]);
    Color myColor = colorManager[key].Clone() as Color;

    Console.ReadLine();
}

输出结果

优缺点


优点

  • 对客户隐藏了具体的产品类,减少了客户知道的产品的数目

  • 客户可以在运行时刻增加和删除产品
  • 改变值以指定新对象,例如通过为一个对象变量指定不同的值并注册为对象的原型
  • 改变结构以指定新对象
  • 减少子类的构造
  • 用类动态配置应用

缺点

  • 每个Prototype子类都必须实现Clone操作,有时会比较困难

浅拷贝与深拷贝


浅拷贝

拷贝一个对象时,仅拷贝对象的引用,拷贝的对象和源对象引用同一份实体。也就是说,改变其中一个对象会影响到另一个对象的状态。

深拷贝

拷贝一个对象时,不仅拷贝对象的引用,还将对象引用的值一同拷贝。这样拷贝的对象和源对象相互独立,其中一个改变不会影响另外一个对象。

使用场景


当一个系统应该独立于它的产品创建、构成和表示时,要使用Prototype模式;以及

  • 当要实例化的类是在运行时刻指定时;或者
  • 为了避免创建一个与产品类层次平行的工厂类层次时;或者
  • 当一个类的实例只能有几个不同状态组合中的一种时
posted @ 2018-05-18 13:09 Answer.Geng 阅读(...) 评论(...) 编辑 收藏