面向对象设计模式之---原型模式(Prototype Pattern)

原型模式的定义是:

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

这个概念看上去很抽象,其实质就是我们在编程中经常用到的对象复制,然后我们不免又要提到一个老生常谈的话题浅复制与深复制

先看一下原型模式的UML类图吧:

这里写图片描述

其中,Prototype是一个原型的抽象类或借口,它里面有一个共有方法,叫clone。ConcretePrototype1与ConcretePrototype2是两个具体的实例,继承或实现了Prototype。这就对应了定义中用原型实例指定创建对象的种类。Client是客户端类,它与Prototype是关联的关系,即在Client类的实例中,有Prototype的对象。客户端可以通过调用Prototype的clone方法来对实现了Prototype的ConcretePrototype1或ConcretePrototype2的对象进行复制来创建新对象,这样比new会有更高的执行效率。

至于它的应有场景,我就拿《大话设计模式》中的例子吧,书中举了一个求职简历的例子,我们投公司一般都是一投好几家,简历也要准备好几份,有的还需要针对公司和职位量身定制部分内容,如果拿软件来生成简历,就比较适合使用原型模式来设计。

现在来谈谈浅复制与深复制的问题,所谓浅复制,简而言之,就是在对象中的非引用类型都会被逐位复制,引用类型复制的是引用,也就是说,在复制后的对象中,如果原有对象中含有引用类型的话,那么复制的对象与原对象指向同一个引用类型,这里的引用类型指的是数组、其他对象实例等。浅复制只做到了原对象与复制对象的相对独立;而深复制就是连引用类型也跟着复制了,原对象与复制对象完全独立。

这个例子我们用java来实现,在Java中有一个借口替我们实现好了Prototype,这个接口叫做cloneable。Sun官方的声明如下

public interface Cloneable
此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常。
按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。请参阅 Object.clone(),以获得有关重写此方法的详细信息。
注意,此接口不 包含 clone 方法。因此,因为某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。

注意红字,也就是说,这个接口告诉计算机,这个类是可复制的。clone默认实现的是浅复制,下面就举一个利用原型模式和cloneable接口实现深复制的例子。在简历中一般包含有工作经验,我们就把它抽象出一个类。

代码实例如下:

import java.util.*;

//工作经验类
class Experience implements Cloneable
{
  private String time;//工作时间
  private String where;//工作地点

  //设置工作经验
  public void setExperience(String time , String where)
  {
    this.time = time;
    this.where = where;
  }

  //显示工作经验
  public String toString()
  {
   return "在"+ where + "工作过,时间为"+time+"\n"; 
  }

  //克隆方法,用于深复制
  protected Object clone()throws CloneNotSupportedException
  {
    return super.clone();
  }

}

//简历类
class Resume implements Cloneable
{
   private String name;//名字
   private int age;//年龄
   private Experience exp;//工作经验

   //构造方法
   public Resume()
   {
     this.exp = new Experience();
   }

   //设置名字
   public void setName(String name)
   {
      this.name = name;
   }

   //设置年龄
   public void setAge(int age)
   {
     this.age = age;
   }

   //设置工作经验
   public void setExp(String time , String where)
   {
      this.exp.setExperience(time,where);
   }

   //显示简历信息
   public String toString()
   {
     return "姓名:"+this.name+" 年龄:"+ this.age+" 工作经验:"+exp.toString();
   }

   //克隆方法
  protected Object clone()throws CloneNotSupportedException
  {
    Resume obj = (Resume)super.clone();
    obj.name = this.name;
    obj.age = age;
    obj.exp = (Experience)this.exp.clone();
    return obj;
  }

}

public class Main
{
  public static void main(String[] args)
  {
    try
    {
      //第一份简历
      Resume r1 = new Resume();
      r1.setName("Martin");
      r1.setAge(23);
      r1.setExp("2016年","Tencent");

      //第二份简历
      Resume r2 = (Resume)r1.clone();
      r2.setExp("2017年","Baidu");

      System.out.println(r1);
      System.out.println(r2);
    }catch(CloneNotSupportedException e)
    {
      e.printStackTrace();
    }
  }
}

运行结果如下:
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值