【设计模式】-06原型模式

1.什么是原型模式?

原型模式是创建对象实例的一种方式,当一个对象需要被重复多次实例化时,可以考虑使用原型模式.原型模式通过创建出一个类的原型,然后调用这个原型对象的克隆方法,从而创建出跟该原型一毛一样的对象.

在传统情况下,我们是通过new来创建对象实例,但如果该对象需要被多次实例化,且实例化后要对其设置一系列初始值时,这时候用传统的做法会降低效率,同时也违背了DRY(don’t repeat youself)原则,如果采用原型模式,就可以让你的代码变得非常优雅又具有效率.

2.为什么要使用原型模式?

①可以让你的系统性能提高.

②可以逃避构造函数的约束.

3.如何实现原型模式?

因为原型模式的实现其实依赖于拷贝,在开始写代码前,我先解释下浅拷贝和深拷贝

浅拷贝:浅拷贝只复制一个对象,传递引用,不能复制实例,对于浅拷贝当对象的成员变量是基本数据类型时,两个对象的成员变量已有存储空间,赋值运算传递值,所以浅拷贝能够复制实例.但是当对象的成员变量是引用数据类型时,就不能实现对象的复制了.

深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值,这个方式称为深拷贝.

如果没太看懂,没关系,下面的例子我会进一步分析:

由于本人是个车迷,梦想能开上保时捷,于是我通过代码创建了一个保时捷,然后将其实例化了,后来我对这一辆保时捷不满足,想批量生产然后卖更多钱,于是我以这辆保时捷为原型,拷贝出N辆一毛一样的保时捷…

/**
 * 保时捷
 */
@Data//这里我用Lombok插件了,如果没有请手动加上get set方法及toString
public class Porsche implements Cloneable {
    private String name;
    private Integer price;
    private String color;
    private Key key;
   /**
     * 浅拷贝克隆
     * @return
     */
    public Object clone() {
        Porsche porsche = null;
        try {
            porsche = (Porsche) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return porsche;
    }

    /**
     * 深拷贝克隆
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public Object deepClone() throws IOException, ClassNotFoundException {
        //将对象写出到流里
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //从流里读进来
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }
}

/**
 * 保时捷车钥匙
 */
@Data
public class Key implements Cloneable {
    private String keyName;
}
/**
 * 测试
 */
public class Client {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //构造保时捷卡宴及车钥匙原型
        Key key = new Key();
        key.setKeyName("保时捷车钥匙");
        Porsche porsche = new Porsche("卡宴", 1000000, "黑色",key);
        System.out.println("原型车:" + porsche);
        //批量生产卡宴
        for (int i = 1; i <= 10; i++) {
            Porsche porschei = (Porsche) porsche.clone();//浅拷贝
//            Porsche porschei = (Porsche) porsche.deepClone();//深拷贝
            if (porschei == porsche) {
                System.out.println("原型和批量生产的车是同一个对象");
            }
            if (porsche.getClass()==porschei.getClass()){
                System.out.println("这是生产的第" + i + "辆卡宴:" + porschei);
            }
            System.out.println(porsche.getKey() == porschei.getKey() ? "每辆车拥有同一把钥匙":"每辆车有各自的钥匙");
        }
    }
}

通过分别注释上面代码中的浅拷贝和深拷贝来测试一下结果如下:

浅拷贝:

《【设计模式】-06原型模式》

深拷贝:

《【设计模式】-06原型模式》

可以看出,深拷贝完成的是真正意义上的拷贝,浅拷贝拷贝后,所有车拥有的是同一把钥匙,这显然不行,10辆保时捷就一把钥匙怎么行,只能通过深拷贝去解决.

4.总结

通过上面的案例,总结下原型模式

原型模式主要包含下面三个角色:

Prototype:抽象原型类,声明克隆自身的接口,对应java.lang.Cloneable接口.

ConcretePrototype:具体原型类,实现克隆的具体操作,对应上面代码中的Porsche.

Client:客户类,客户类提出创建对象的请求,从而获得一个或多个新的对象,对应上面代码中的Client.

Object是所有类的爸爸,它提供了clone()方法,子类们可以调用父类的clone()方法进行浅拷贝,一般而言,clone()方法满足: 

(1) 对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象,但如果原对象中存在对其他对象的引用,该引用对象与原对象是同一个对象. 

(2) 对任何的对象x,都有x.clone().getClass()==x.getClass(),即克隆对象与原对象的类型一样.

(3) 如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立.

如果要实现深度克隆,原型及原型引用的对象均需要实现Serializable序列化接口.

 

    原文作者:设计模式
    原文地址: https://blog.csdn.net/lovexiaotaozi/article/details/84070502
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞