[程序员的自我修养-做一个牛逼的程序员,就得从设计模式入手]-原型模式

写这期原型模式时,心里是很忐忑的。因为前两天996的原因,精神不是很好。在看了别人写的模式介绍时,觉得大师们有自己的深刻理解,总说一些我没有听过的概念。就没有了写下去的勇气了。其实,就是从了心,怂了。但是一切的理所当然不都是自己一股劲儿闯出来的吗。所以,依然还是写了。

 

以下,个人理解的原型模式。

原型模式,如果究其字面的意思,就是有一个母体,别的类都是通过它克隆出来的。我就把关键词克隆记住,觉得在以后回忆的时候会更快想起这是一个什么样的模式。

万物有其源,比方说我就是想吃个包子,我可以自己学和面,和馅儿,再上锅去蒸。甚至说我是世界上第一个会做包子的,我的第一个包子就是这个世界所有包子的prototype。而我就是一个构造器。那么别人想吃包子,不用自己包,可以在我这买,那和我的第一个包子类似的其它小包子就诞生了。在创建类上这样做就很高效。原型模式其实也反映了我们社会的一种活动形式-借用别人的成果,相互依赖。单打独斗带来的收获不会很高。反正我是不会为了早上的一盒牛奶去内蒙养牛的。绝不。

我一般喜欢抽出关键词来说明重点。这里的重点是 原型类(prototype),克隆(clone),client(使用者) 这三个就是葵花宝典里的第一章了-最精要的部分。如果配合其它的设计模式,还可以加上一个管理者(manager)的角色。

prototype是个苦命的人儿,什么苦活,累活都是她的。当需要一个对象时,最常见的就是new 一个出来。不是什么事儿都轻而易举的。你想拉个shit,你只要用力new 一个Shit对象就行,不限时间,地点,你开心就行。但是你要吃个饭,要自己做,就得买菜,煮菜;出去吃,得开车,得化妆,这是一个花时间的过程。这就是建立一个prototype会遇到的情况。这个流程不可避免。

但是如果个个在new的时候,都要一顿操作猛如虎,那就不是我们追求的了。

所以,我们要学会克隆(这个要像某讯学习,这个模式,他们学得最好,copycat的代言人),通过克隆或者拷贝获得一个和原型一样的新对象。把原来prototype经历的那些痛苦都免了。吃现在成的。

在极其考验性能的场景,这是很宝贵的。

下面,代码说明。

/**
 * 原型类 所有的类型都以它作为原型创建
 * 实现Clonable是这个模式的关键, 使用 jkd 11 编辑
 */
public class VehiclePrototype implements Cloneable, Serializable {

    private String brand;

    private String name;

    private Double price;

    public VehiclePrototype() {
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getName() {
        return name;
    }

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

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "VehiclePrototype{" +
                "brand='" + brand + '\'' +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    /**
     * 两种克隆模式 浅拷贝仅复制内部对象地址;若要隔绝类之间的数据冲突,不要使用浅拷贝;这个坑可不浅;
     */
    public VehiclePrototype copy() {
        try {
            return (VehiclePrototype) this.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            //
        }
        return null;
    }

    /**
     * 深拷贝 这是目前我能找到的百分百有效的深拷贝实现;可以将目标类和原型类的所有属性进行隔离;不相互影响;一个字,稳
     * 高能!!!!!!序列化你不实现Serializable可不行
     */

    public VehiclePrototype deepCopy() {
        //使用数组流进行对象的序列化存储
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        //使用对象输出流将当前对象写出到数组流中
        try {
            // 这个写法建议朋友们自己手写一次;第一次记的时候会有点绕;我一般会把带有input的当成自己;这些stream操作的就是进食;带有Output的就是那个往外排(想象那个画面吧);这样时间一久,我也能快速回忆起他们的用法;这个是我的记忆方法
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            //关闭流;别忘了
            oos.close();
            ois.close();
            return (VehiclePrototype) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

这里我只写了一个原型类,现实中很多的情况是有多个子类的,这里的车可以有卡车,汽车等等。最为重要的一点是这里代码实现的细节,原理呢就是通过深拷贝或浅拷贝实现,但是呢,手动撸一次你会发现我在注释中说到的一些问题。要记得住才行。

下面是对深浅拷贝的一个实现对比。这里就涉及到java基础的东西了。关于clone和序列化方式带来的不同拷贝效果的对比。

 

/**
 * 这是demo类,来看看这个模式下怎么做到高效的生成新对象的
 */
public class Client {

    public static void main(String[] args) {
        // 自己可以想象用最原始的方法创造了一个原型类;可能花费了1分钟;但是后面要用到这样的类千万个
        VehiclePrototype prototype = new VehiclePrototype();
        //先给这个原型打上一些标记
        prototype.setBrand("AUDI");
        prototype.setName("A8L");
        prototype.setPrice(40_0000.00);

        System.out.println("prototype: before  " + prototype);

        //立马用两个方法进行拷贝操作
        VehiclePrototype copycat = prototype.copy();
        copycat.setBrand("ALTO");
        copycat.setName("NINE_HAND");
        copycat.setPrice(3000.00);

        //这个是深拷贝
        VehiclePrototype lamborghini = prototype.deepCopy();
        lamborghini.setName("GALLARDO");
        lamborghini.setBrand("LAMBORGHINI");
        lamborghini.setPrice(500_0000.00);
 
//        prototype: before  VehiclePrototype{brand='AUDI', name='A8L', price=400000.0}
//        prototype: after1  VehiclePrototype{brand='AUDI', name='A8L', price=400000.0}
//        copycat:  before VehiclePrototype{brand='ALTO', name='NINE_HAND', price=3000.0}
//        lamborghini: before  VehiclePrototype{brand='LAMBORGHINI', name='GALLARDO', price=5000000.0}
//        prototype: after2  VehiclePrototype{brand='AUDI', name='new Name', price=400000.0}
//        copycat: after  VehiclePrototype{brand='ALTO', name='NINE_HAND', price=3000.0}
//        lamborghini: after  VehiclePrototype{brand='LAMBORGHINI', name='GALLARDO', price=5000000.0}
    }
}

那这里只是说明了原型模式所使用的关键代码,但是从大局来说,这样还不行。

从整体上来说,我的理解是原型模式很像一个可以快速拿到货物的仓库,比如说某东的仓库(虽然这两天某东处于风口浪尖,但是他的物流还行)。如果说电脑是一个原型,那我可以把小米的电脑,华硕的电脑,神舟的电脑作为它的子类,它们也是原型啊。不光这样,我设计一个叫ProtypeFactory的工厂,可以根据条件查询到对应的原型。因为这里的原型的获取方式更快了,这就带来了效率的提升。所以,我们在学习使用设计模式的时候不能一招定死,要和其它模式联合使用。打拳的如果一次出手只用一路拳法,是没法赢的。

作为一个建造类型的模式,原型模式节约了获取对象的时间。但是也要考虑到子类一旦增多后,所带来的属性等的扩展成本。

理解有限,这是我看过了别人的说明后,自己又写了两遍代码的感悟。算不上有深度,但又让我的认识上了一个高度。

还是那句话,看过别人说明之后,一定要用自己的语言再把这个内容给教给别人一遍,等到你说明白这个概念所用的时间越来越少的时候,就真的掌握它了(这可是现在世界上最好的学习法了,小伙伴们用起来~!)。如果文中你发现了一些错误,还请指正,毕竟,我的认知也是有限的。

我是杰森小哥,每天学习一点儿,才能看到更大的世界~~

 

你可能感兴趣的:(个人笔记)