设计模式之原型模式

原型模式

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式属于创建型模式,前面已经讲了四个创建型模式,原型模式是最后一个。通过定义描述,不难理解原型模式相当于复制对象,避免复杂对象的初始化过程。

这里写图片描述

从图上看,原型模式非常简单。只要具体类实现Cloneable接口,覆盖Object类下都有的clone方法。clone方法是通过jni调用,虚拟机会调用已实现Cloneable接口的类中的clone方法,所以clone方法必须覆盖,不然会报错。不需要我们知道原理,总之就是复制对象。

 protected native Object clone() throws CloneNotSupportedException;

举个汽车的例子。通常汽车都有发动机、轮胎、类型、颜色等等。同个类型的汽车配置大多都是一样的,而也有些区别。比如白色奔驰和黑色奔驰,只是颜色不一样。这时白色奔驰作为参考,再新造黑色奔驰,相当于复制一辆奔驰,改变颜色。

代码示例

    public class Car implements Cloneable {

        private String type;
        private String color;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getColor() {
            return color;
        }

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

        protected Object clone(){//覆盖clone方法
            try {
                return super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

客户端

    Car car1 = new Car();
    car1.setType("奔驰");
    car1.setColor("白色");
    System.out.println(car1.getColor()+car1.getType()+car1.toString());//输出 白色奔驰Car@659e0bfd
    Car car2 = (Car) car1.clone();
    car2.setColor("黑色");
    System.out.println(car2.getColor()+car2.getType()+car2.toString());//输出 黑色奔驰Car@15db9742

从代码可以看到,car1拷贝car2,car2还带有car1的属性,而且两个对象指向的不是同一个内存地址,所以各自修改也不影响对方。这就是clone作用。

深拷贝

如果我新增一个引擎类,作为Car的属性。引擎名字默认为default。

    public class Engine{

        private String name = "default";

        public String getName() {
            return name;
        }

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

    public class Car implements Cloneable {
        //...
        private Engine engine = new Engine();

        public Engine getEngine() {
            return engine;
        }
    }

客户端

    Car car1 = new Car();
    System.out.println(car1.getEngine().getName() + car1.getEngine().toString());
    Car car2 = (Car) car1.clone();
    car2.getEngine().setName("new");
    System.out.println(car2.getEngine().getName() + car2.getEngine().toString());
    System.out.println(car1.getEngine().getName() + car1.getEngine().toString());

输出为:

    defaultEngine@659e0bfd
    newEngine@659e0bfd
    newEngine@659e0bfd

可以看出里面的实例都是一样的,引用地址是同一块区域所以当car1的engine改变,car2的engine也跟着改变,这也不符合我们的使用原型初衷。这叫浅拷贝,只能拷贝基本类型不能拷贝对象。当然也有解决方案,有浅就有深,称为深拷贝。做法是需要被拷贝对象实现Cloneable接口,覆盖clone方法。然后在拷贝的地方调用被拷贝对象的clone方法。

    public class Engine implements Cloneable {
        //...
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

    public class Car implements Cloneable {
        //...
        protected Object clone(){
                try {
                    Car car = (Car) super.clone();
                    car.engine = (Engine) engine.clone();//调用该属性的clone方法
                    return car;
                } catch (CloneNotSupportedException e) {
                    e.printStackTrace();
                }
                return null;
            }
    }

客户端代码不改,编译运行,得出的是我们想要的结果。

总的来说,应用在创建多次重复对象时或者耗时的对象初始化,原型模式可以不受构造器的约束,减少初始化的开销。只要被拷贝的对象实现Cloneable接口并且覆盖clone方法即可。原型模式分为浅拷贝和深拷贝,使用情况取决于内部实例是否重新指定新的内存区域。不足之处望指教。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值