java设计模式-----原型模式

1、引言

    原型(Prototype)模式是一种对象建立型模式,他采起复制原型对象的方法来建立对象的实例。使用原型模式建立的实例,具备与原型同样的数据java

原型模式的特色:设计模式

  1. 由原型对象自身建立目标对象。也就是说,对象建立这一动做发自原型对象自己。
  2. 目标对象是原型对象的一个克隆。也就是说,经过原型模式建立的对象,不只仅与原型对象具备相同的结构,还与原型对象具备相同的值。
  3. 根据对象克隆深度层次的不一样,有浅度克隆与深度克隆。

  先写一个支持克隆的类安全

//若是要克隆就必须实现Cloneable接口
public class Person implements Cloneable{
    //可能会抛出不支持克隆异常,缘由是没有实现Cloneable接口
    @Override
    protected Person clone(){
        try{
            return (Person) super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
            return null;
        }
    }
}

这个样子,就说明这个类能够克隆了。ide

  这样克隆函数

public class MainClass {
    public static void main(String[] args) {
        Person person1 = new Person();
        
        Person person2 = person1.clone();
    }
}

       这样子克隆并不等同于Person p2 = p1;像Person p2 = p1;指的是在栈中建立一个变量p2,将p1的内存地址赋给p2,其实指的是同一个对象。而克隆是复制出一份如出一辙的对象,两个对象内存地址不一样,但对象中的结构与属性值如出一辙。this

  这种不经过 new 关键字来产生一个对象,而是经过对象拷贝来实现的模式就叫作原型模式,这个模式的核心是一个clone( )方法,经过这个方法进行对象的拷贝,Java 提供了一个 Cloneable 接口来标示这个对象是可拷贝的,为何说是“标示”呢?翻开 JDK 的帮助看看 Cloneable 是一个方法都没有的,spa

这个接口只是一个标记做用,在 JVM 中具备这个标记的对象才有可能被拷贝,因此覆盖了覆盖clone()方法就能够了。.net

  在 clone()方法上增长了一个注解@Override, 没有继承一个类为何能够重写呢?在 Java 中全部类的父类是Object 类,每一个类默认都是继承了这个类,因此这个用上@Override是很是正确的。原型模式虽然很简单,可是在 Java 中使用原型模式也就是 clone 方法仍是有一些注意事项的:设计

  对象拷贝时,类的构造函数是不会被执行的。 一个实现了 Cloneable 并重写了 clone 方法的类 A,有一个无参构造或有参构造 B,经过 new 关键字产生了一个对象 S,再而后经过 S.clone()方式产生了一个新的对象 T,那么在对象拷贝时构造函数 B 是不会被执行的, 对象拷贝时确实构造函数没有被执行,这个从原理来说也是能够讲得通的,Object 类的 clone 方法的 原理是从内存中(具体的说就是堆内存)以二进制流的方式进行拷贝,从新分配一个内存块,那构造函数 没有被执行也是很是正常的了。code

还有就是深度克隆与浅度克隆

首先,是浅度克隆

//若是要克隆就必须实现Cloneable接口
public class Person implements Cloneable{
    private String name;
    private String sex;
    private List<String> list;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    //可能会抛出不支持克隆异常,缘由是没有实现Cloneable接口
    @Override
    protected Person clone(){
        try{
            return (Person) super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
            return null;
        }
    }
}

这就是浅度克隆,当被克隆的类中有引用对象(String或Integer等包装类型除外)时,克隆出来的类中的引用变量存储的仍是以前的内存地址,也就是说克隆与被克隆的对象是同一个。这样的话两个对象共享了一个私有变量,全部人均可以改,是一个种很是不安全的方式,在实际项目中使用仍是比较少的。

因此就要说到深度拷贝

//若是要克隆就必须实现Cloneable接口
public class Person implements Cloneable{
    private String name;
    private String sex;
    private List<String> list;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    //可能会抛出不支持克隆异常,缘由是没有实现Cloneable接口
    @Override
    protected Person clone(){
        try{
            Person person = (Person) super.clone();
            List<String> newList = new ArrayList();
            
            for(String str : this.list){
                newList.add(str);
            }
            person.setList(newList);
            return person;
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
            return null;
        }
    }
}

这样就完成了深度拷贝,两种对象互为独立,属于单独对象。

注意:final 类型修饰的成员变量不能进行深度拷贝  

  最后说一下,原型模式的使用场景

  一、在建立对象的时候,咱们不仅是但愿被建立的对象继承其基类的基本结构,还但愿继承原型对象的数据。

  二、但愿对目标对象的修改不影响既有的原型对象(深度克隆的时候能够彻底互不影响)。

  三、隐藏克隆操做的细节,不少时候,对对象自己的克隆须要涉及到类自己的数据细节。

  四、类初始化须要消化很是多的资源,这个资源包括数据、硬件资源等;

  五、经过 new 产生一个对象须要很是繁琐的数据准备或访问权限,则可使用原型模式;

  六、一个对象须要提供给其余对象访问,并且各个调用者可能都须要修改其值时,能够考虑使用原型模式拷贝多个对象供调用者使用。在实际项目中,原型模式不多单独出现,通常是和工厂方法模式一块儿出现,经过 clone的方法建立一个对象,而后由工厂方法提供给调用者。原型模式先产生出一个包含

  大量共有信息的类,而后能够拷贝出副本,修正细节信息,创建了一个完整的个性对象。

2、总结

        原型模式能够说是全部设计模式中最简单的一个,它没有复杂的继承体系,只须要使须要具备拷贝功能的类实现Cloneable接口并重写clone()方法便可。但它的应用却及其普遍,它将对一个对象中各个字段(不论是私有的仍是共有的)的复制操做封装在了clone()方法中,这样,使用该类的用户就不须要对对象中的各个字段的细节进行了解,直接调用clone()方法就能够实现对象的拷贝,并且,经过clone()方法还能够为不一样的字段设置被复制的权限,从而容许仅对能够被复制的字段进行复制。

 

真正勇敢的人,应当可以智慧地忍受最难堪的荣辱,不以身外的荣辱介怀,用息事宁人的态度避免无谓的横祸。 —— 莎士比亚

相关文章
相关标签/搜索