设计模式三十六计之原型模式(Prototype)

image

设计模式三十六计之原型模式(Prototype)

1. 设计思想

将一个对象作为指定的原型实例,并通过克隆此原型来创建新的对象

2. 演示案例

关于克隆,大家都知道克隆羊‘克隆羊多利’ ,本章节我们就以‘克隆羊多利’ 来演示原型模式

简而言之

原型模式就是克隆现有的对象来创建新的对象

百度百科:

原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

原型模式允许你创建现有对象的副本并更具实际需要进行修改,而不是从头开始创建新的对象并进行设置。

3. 代码示例

在Java中,一个对象只需要实现Cloneable接口,覆写clone方法,此clone方法名可以自定义,就可以完成原型模式的设计。
首先我们创建一个Sheep类并实现Cloneable接口:

 public class Sheep implements Cloneable{
   private String name;

   public Sheep(String name){
     this.name = name;
   }

   public void setName(String name){
     this.name = name;
   }

   public String getName(){
     return this.name;
   }

   /**
    * 覆写clone方法
   **/
   @Override
   public Sheep clone() throws CloneNotSupportedException{
     return new Sheep(name); //此处是关键
   }

 }

然后我们可以通过如下的方式来克隆一个对象并进行修改:

  public class TestPrototype{
    public static void main(String[] args){
      Sheep oldSheep = new Sheep("oldSheep");
      System.out.println(oldSheep.getName());

      //根据需要对oldSheep进行克隆和修改
      Sheep cloneSheep = oldSheep.clone();
      cloneSheep.setName("cloneSheep");

      System.out.println(cloneSheep.getName());
    }
  }

输入内容:

  oldSheep
  cloneSheep

4. 适用范围

  • 当系统独立于其他产品的创建、组合和表示方式的时候
  • 当要在运行时指定实例化的类时,例如动态加载类
  • 当需要避免重复创建结构相似的工厂类的时候
  • 当一个类的实例可以有几个不同的状态组合时,创建相应数量的原型对象并进行克隆的方式比手动实例化类要简单得多。
  • 当需要降低系统开销时。克隆对象的成本要比创建对象低很多

5. 浅克隆与深克隆

原型模式涉及到 浅克隆深克隆 的概念 。首先我们通过代码来演示来说明什么是浅克隆。定义一个Sheep类实现Cloneable接口,并覆写clone方法,且在原来的代码基础上增加一个Color属性:

package com.ramostear.pattern.prototype;
/**
 * @author ramostear
 * @create-time 2019/1/4 0004-14:44
 * @modify by :ramostear
 * @info:[原型类:Sheep]
 * @since:
 */

public class Sheep implements Cloneable{

    private String name;

    private  Color color = new Color();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Sheep(String name) {
        this.name = name;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Sheep sheep = (Sheep)super.clone();
        return sheep;
    }

}

说明:代码中增加了Color类的引用,Color类中什么都没有定义,只是一个空的类。

测试代码:

package com.ramostear.pattern.prototype;
/**
 * @author ramostear
 * @create-time 2019/1/4 0004-14:50
 * @modify by :ramostear
 * @info:[浅克隆测试代码]
 * @since:
 */

public class TestPrototype {

    public static  void main(String[] args) throws CloneNotSupportedException{
        Sheep sheep1 = new Sheep("sheep1");
        Sheep sheep2 = (Sheep) sheep1.clone();
        System.out.println("print hashcode ...");
        System.out.println("sheep1`s hashcode:"+sheep1.hashCode());
        System.out.println("sheep2`s hashcode:"+sheep2.hashCode());

        System.out.println("print color ...");
        System.out.println("sheep1`s color:"+sheep1.getColor().hashCode());
        System.out.println("sheep2`s color:"+sheep2.getColor().hashCode());
    }
}

控制台输出结果:


控制台输出

从输出结果可以看到,我们对sheep1进行了克隆,得到sheep2,此时的sheep2是一个全新的引用,但由于Sheep类中加入了另外的一个引用 Color,所以sheep1和sheep2对Color的引用还是同一个,输出的hashcode都为'356573597',证明Color的引用没有连带克隆,这就是浅克隆。

如何做到连同Color对象一起克隆而不是指向同一个引用?这就是接下来要讲的深克隆

首先我们对Color类进行一些改造,让Color类同样实现Cloneable接口,并覆写clone方法。

package com.ramostear.pattern.prototype;
/**
 * @author ramostear
 * @create-time 2019/1/4 0004-15:08
 * @modify by : ramostear
 * @info:[Color类,实现Cloneable接口]
 * @since:
 */
public class Color implements  Cloneable{
    private String color;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Color color = (Color)super.clone();
        return color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public Color(String color) {
        this.color = color;
    }
    public Color(){}
}

然后对Sheep的clone方法进行一些调整

package com.ramostear.pattern.prototype;
/**
 * @author ramostear
 * @create-time 2019/1/4 0004-14:44
 * @modify by :ramostear
 * @info:[原型类:Sheep]
 * @since:
 */

public class Sheep implements Cloneable{

    private String name;

    private  Color color = new Color();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Sheep(String name) {
        this.name = name;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Sheep sheep = (Sheep)super.clone();
        //增加了对color的设置
        sheep.color = (Color) color.clone();
        return sheep;
    }
}

测试代码保持不变:

package com.ramostear.pattern.prototype;
/**
 * @author ramostear
 * @create-time 2019/1/4 0004-14:50
 * @modify by :ramostear
 * @info:[浅克隆测试代码]
 * @since:
 */

public class TestPrototype {


    public static  void main(String[] args) throws CloneNotSupportedException{
        Sheep sheep1 = new Sheep("sheep1");
        Sheep sheep2 = (Sheep) sheep1.clone();
        System.out.println("print hashcode ...");
        System.out.println("sheep1`s hashcode:"+sheep1.hashCode());
        System.out.println("sheep2`s hashcode:"+sheep2.hashCode());

        System.out.println("print color ...");
        System.out.println("sheep1`s color:"+sheep1.getColor().hashCode());
        System.out.println("sheep2`s color:"+sheep2.getColor().hashCode());
    }
}

输出结果:


控制台输出

从输出结果可以看到,我们对sheep1进行了克隆,得到sheep2,此时的sheep2是一个全新的引用,且sheep2的color也是一个全新的引用,至此,我们就实现了原型模式的深克隆。

6. Java中的实际案例

[原文链接:https://www.ramostear.com/articles/prototype.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容