设计模式(Java语言)- 原型模式

  原型模式(Prototype Pattern)也有人将原型模式称为克隆模式,是属于创造型设计模式,用于建立重复的对象,提供了一种建立对象的最佳方式。原型模式须要实现Cloneable接口,来实现对象的克隆。在实际的应用中,若是应用须要反复建立相同的对象时,而且建立这个对象须要花费大量时间或者须要访问权限,好比须要读取数据库,配置文件等,若是每次建立重复对象都须要读一次数据库,那么这种方式显然并非高效的。这时能够考虑使用原型模式来解决,提升效率,此时只须要在建立原型对象时须要读取一次数据库或配置文件等,当后面须要须要建立这个对象时只须要从原型对象克隆一个出来便可。另外,原型模式也解决了构建复杂对象时繁琐的过程,原型模式不关心对象建立的细节,用户只须要调用克隆的方法就能够建立出一个一摸同样的对象,简化建立流程。java

  既然原型模式也成为克隆模式,那么对象复制过程必然用到Java的克隆方法。因此你也须要了解什么是浅克隆和深克隆。数据库

  浅克隆

  浅克隆复制的是对象基本类型的属性,对于引用类型的属性,浅克隆置复制该应用类型的地址,由于克隆对象的被克隆对象的应用类型属性是同一个内存地址,即为同一个对象,因此在修改其中一个对象的该属性时,另外一个对象的改属性也会被修改,很容易将原型对象属性修改,这也是在使用原型模式时须要注意的地方。浅克隆在代码中的实现也比较简单,Java语言中自己就已经提供相关的接口和方法了,咱们在使用时只须要继承Cloneable接口,重写clone方法便可实现对象的浅克隆。代码实现以下:设计模式

public class Sheep implements Cloneable {

    private String name;
    private Color color = new Color();

    public Sheep() {
    }

    public Sheep(String name, String color) {
        this.name = name;

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

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", color=" + color +
                '}';
    }

    public Color getColor() {
        return color;
    }

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

    public String getName() {
        return name;
    }

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

  

public class Color implements Cloneable {

    private String color;

    public Color() {
    }

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

    public String getColor() {
        return color;
    }

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

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

    @Override
    public String toString() {
        return "Color{" +
                "color='" + color + '\'' +
                '}';
    }
}

  测试ide

public class Test {

public static void main(String[] args) throws CloneNotSupportedException {
Sheep test = new Sheep("test","白色");
System.out.println(test);
Sheep clone = (Sheep) test.clone();
clone.setColor("黑色");
clone.setName("test01");
System.out.println(test);
System.out.println(clone);
}

}

  运行程序时控制台打印出了:测试

  Sheep{name='test', color=Color{color='白色'}}优化

  Sheep{name='test', color=Color{color='黑色'}}this

  Sheep{name='test01', color=Color{color='黑色'}}设计

  很显然,test对象建立时是白色的,而后用这个对象进行克隆获得 clone 实例,而后将clone 对象的颜色修改为黑色,name修改为test01,最终两个对象的颜色都变成了黑色,印证了上面说的话,对于引用类型克隆的是对象的内存地址。可能会有人好奇,String也是引用类型,为何克隆对象修改了name属性,原型对象却没有被修改了?这是由于String是final类型,克隆过程当中天然会是两个不一样的内存地址。对象

 

  深克隆

  深克隆和浅克隆的区别在于,深克隆时引用类型属性复制的是该属性的值,与原型对象的拥有不一样的内存地址,即两个是不一样的对象,他们任意一个改属性值都不会影响到彼此。深克隆的实现方式有两种,第一种,实现Cloneable接口,重写clone方法,与浅克隆不一样的是多一步将引用类型的变量再调用一次改变量的clone方法。不推荐用这种方法实现深克隆,每次修改对象的变量时都须要修改一次clone方法,违反了ocp原则。第二种,利用Java序列化与发序列化来实现,推荐使用这种方式。blog

  代码实现:

public class Color implements Cloneable, Serializable {

    private String color;

    public Color() {
    }

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

    public String getColor() {
        return color;
    }

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

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

    @Override
    public String toString() {
        return "Color{" +
                "color='" + color + '\'' +
                '}';
    }
}

  

public class Sheep implements Cloneable, Serializable {

    private String name;
    private Color color = new Color();

    public Sheep() {
    }

    public Sheep(String name, String color) {
        this.name = name;

        setColor(color);
    }

    /**
     * 利用序列化与反序列化实现深克隆
     * @return
     */
    public Object deepClone() {
        ByteArrayInputStream bis = null;
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);


            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            return ois.readObject();
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (ois != null) {
                    ois.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (oos != null) {
                    oos.close();
                }
                if (bos != null) {
                    bos.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

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

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", color=" + color +
                '}';
    }

    public Color getColor() {
        return color;
    }

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

    public String getName() {
        return name;
    }

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

  注意,若是使用Java的序列化与反序列化,则改对象须要实现Serializable接口,不然会抛序列化异常。

  

  总结

  一、原型模式有两种实现方式,第一种利用Object类中的clone方式,重写Cloneable的clone方法,浅克隆时直接调用Object类提供的clone方式便可。深克隆则须要再调用须要被克隆的对象的clone方法,固然该对象也必须实现Cloneable接口。第二种方式是利用Java的序列化和反序列化技术,这种方式也有一个缺点是全部须要序列化的变量都必需要实现Serializable接口。

  二、原型模式的优势:提升效率;屏蔽复杂的对象构建过程,简化代码。

  三、原型模式的缺点:

    1)配备克隆方法须要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不必定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。

    2)必须实现 Cloneable 接口或Serializable接口。

  四、原型模式的应用场景:

    1)资源优化场景。

    2)对象初始化须要大量的资源,包括数据,硬件资源等。

相关文章
相关标签/搜索