• java设计模式-原型模式


    Java原型模式

    1、概述

      啥是原型模式?

      原型模式属于设计模式中的创建型中的一员,

      原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象!

      说大白话就是自己复制自己,通过原生对象复制出一个新的对象,这两个对象结构相同且相似;

      需要注意的是,原型对象自己不仅是个对象还是个工厂!并且通过克隆方式创建的对象是全新的对象,它们都是有自己的新的地址,通常对克隆模式所产生的新对象进行修改,是不会对原型对象造成任何影  响的,每一个克隆对象都是相对独立的,通过不同的方式对克隆对象进行修改后,可以的到一系列相似但不完全相同的对象。

    2、原型UML图

     

    3、深克隆与浅克隆

      原型模式中又可细分为浅克隆和深克隆;

      浅克隆:在浅克隆中,如果原型对象的成员变量是值类型(八大基本类型,byte,short,int,long,char,double,float,boolean).那么就直接复制,如果是复杂的类型,(如枚举、对象)就只复制对应的内存地址。

      深克隆:就是什么都是单独的!全部复制,然后各自独立,修改克隆对象对于原型对象没有任何影响,对于深克隆具体克隆多深取决于业务需求和类结构设计。

    4、代码案例

      4.1、先来一个简单小案例热热身

      这个浅克隆比较简单,让我们由浅入深的学习原型模,先看下这个有助于理解深克隆,废话不多说直接上代码

    package pattern.prototype.demo;
    /**
     * 苹果原型类,这就是我们要复制的对象类
     * 要想克隆一个实例必须要实现Cloneable接口,否则会抛出异常(java.lang.CloneNotSupportedException),
     * @author ningbeibei
     */
    public class Apple implements Cloneable{
        //苹果品种
        public String variety;
        //数量
        public int no;
        
        //添加克隆这个对象的方法,
        public Apple cloneApple() {
            Object obj =null;
            try {
                obj = super.clone();
                return (Apple) obj;
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
        
        public String getVariety() {
            return variety;
        }
        public void setVariety(String variety) {
            this.variety = variety;
        }
        public int getNo() {
            return no;
        }
        public void setNo(int no) {
            this.no = no;
        }
    }

      测试下,看结果是不是很简单,只需要实现Cloneable接口调用clone方法就OK

    package pattern.prototype.demo;
        
    public class test {
        public static void main(String[] args) {
            Apple a= new Apple();
            a.setVariety("富士苹果");
            System.out.println("原型对象:"+a);
            Apple b = a.cloneApple();
            System.out.println("克隆出来的新对象:"+b);
            System.out.println("两个对象是否相等:"+(a == b));
            b.setVariety("红星苹果");
            System.out.println("两个对象的苹果品种:"+b.getVariety()+"、"+a.getVariety());
        }
    }

      结果输出

      4.2、深克隆和浅克隆案例

      代码中案例我已组装电动车为例,要组装电动车必须有这几个组件,电车架子、蓄电池、手刹、钢丝,有了这些组件我们来捋一下他们的关系,组装电车需要把蓄电池和手刹装在电车上,组装手刹需要用到钢丝绳,他们是一个包含关系即:电车架子>蓄电池>手刹>钢丝,请看下面代码。

      (1),先定义克隆接口

    package pattern.prototype;
    /**
     * 定义原型模式接口
     * @author ningbeibei
     *
     */
    public interface ProtoType {
        //浅克隆
        ProtoType getShallowCloneInstance()throws CloneNotSupportedException;
        //深克隆
        ProtoType getDeepCloneInstance(ProtoType protoType);
    }

      (2),定义深克隆工具类,通过序列化方式复制对象

    package pattern.prototype;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    /**
     * 原型模式工具类
     * @author ningbeibei
     */
    public class ProtoTypeUtil {
    
        /**
         * 通过序列化方式获取一个深克隆对象
         * 其实就是复制一个全新的对象并且这个对象的引用属性也会单独复制出来
         * 与原对象没有任何关联
         * @param prototype
         * @return
         */
        public static ProtoType getSerializInstance(ProtoType prototype) {
            try {
                //创建输出流
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(bos);
                oos.writeObject(prototype);
                //创建输入流
                ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bis);
                ProtoType copy = (ProtoType) ois.readObject();
                bos.flush();
                //关闭输出流
                bos.close();
                //关闭输入流
                ois.close();
                return copy;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }

      (3),定义电动车骨架类(属性中有手刹蓄电池组件)

    package pattern.prototype;
    
    import java.io.Serializable;
    
    /**
     * 定义电动车类
     * 组装一个电动车需要手刹蓄电池等部件
     * 要实现深克隆需要允许序列化反序列化操作
     * Cloneable :要想使用clone方法必须实现这个接口,否则会抛出异常(java.lang.CloneNotSupportedException)
     * Serializable:允许序列化反序列化对象,通过序列化复制一个新的对象(深克隆会用到)
     * ProtoType:自定义接口,接口中提供浅克隆方法和深克隆方法
     * @author ningbeibei
     */
    public class Bicycle implements Cloneable,Serializable,ProtoType{
        //电动车品牌
        public String brand;
        //电动车生产编号
        public int no;
        //手刹组件
        public ParkingBrake parking;
        //蓄电池
        public Accumulator accumulator;
        
        /**
         * 浅克隆方法
         */
        @Override
        public ProtoType getShallowCloneInstance() {
            Object obj=null;
            try {
                obj = super.clone();
                return (Bicycle)obj;
            } catch (CloneNotSupportedException e) {
                System.out.println("不支持克隆");
                return null;
            }
        }
    
        /**
         * 深克隆方法
         * 调用工具类ProtoTypeUtil.getSerializInstance方法复制一个新的对象
         */
        @Override
        public ProtoType getDeepCloneInstance(ProtoType protoType) {
            //调用工具类中的序列化对象方法复制对象
            return ProtoTypeUtil.getSerializInstance(protoType);
        }
        
        public String getBrand() {
            return brand;
        }
        public void setBrand(String brand) {
            this.brand = brand;
        }
        public int getNo() {
            return no;
        }
        public void setNo(int no) {
            this.no = no;
        }
        public ParkingBrake getParking() {
            return parking;
        }
        public void setParking(ParkingBrake parking) {
            this.parking = parking;
        }
        public Accumulator getAccumulator() {
            return accumulator;
        }
        public void setAccumulator(Accumulator accumulator) {
            this.accumulator = accumulator;
        }
    }

      (4),定义蓄电池类

    package pattern.prototype;
    
    import java.io.Serializable;
    
    /**
     * 电车组件:蓄电池
     * @author ningbeibei
     */
    public class Accumulator implements Serializable,ProtoType,Cloneable{
        //蓄电池品牌
        public String brand;
        //出厂编号
        public int no;
        
        /**
         * 浅克隆方法
         */
        @Override
        public ProtoType getShallowCloneInstance() {
            Object obj=null;
            try {
                obj = super.clone();
                return (Bicycle)obj;
            } catch (CloneNotSupportedException e) {
                System.out.println("不支持克隆");
                return null;
            }
        }
    
        /**
         * 深克隆方法
         * 调用工具类ProtoTypeUtil.getSerializInstance方法复制一个新的对象
         */
        @Override
        public ProtoType getDeepCloneInstance(ProtoType protoType) {
            //调用工具类中的序列化对象方法复制对象
            return ProtoTypeUtil.getSerializInstance(protoType);
        }
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public int getNo() {
            return no;
        }
    
        public void setNo(int no) {
            this.no = no;
        }
    }

      (5),定义手刹类(手刹类属性中有钢丝组件)

    package pattern.prototype;
    
    import java.io.Serializable;
    
    /**
     * 电动车组件:手刹
     * @author ningbeibei
     */
    public class ParkingBrake implements Serializable, ProtoType,Cloneable {
        //手刹品牌
        public String brand;
        //出厂编号
        public int no;
        //钢丝
        public SteelWire steel;
        
        /**
         * 浅克隆方法
         */
        @Override
        public ProtoType getShallowCloneInstance() {
            Object obj=null;
            try {
                obj = super.clone();
                return (Bicycle)obj;
            } catch (CloneNotSupportedException e) {
                System.out.println("不支持克隆");
                return null;
            }
        }
    
        /**
         * 深克隆方法
         * 调用工具类ProtoTypeUtil.getSerializInstance方法复制一个新的对象
         */
        @Override
        public ProtoType getDeepCloneInstance(ProtoType protoType) {
            //调用工具类中的序列化对象方法复制对象
            return ProtoTypeUtil.getSerializInstance(protoType);
        }
        
        public String getBrand() {
            return brand;
        }
        public void setBrand(String brand) {
            this.brand = brand;
        }
        public int getNo() {
            return no;
        }
        public void setNo(int no) {
            this.no = no;
        }
        public SteelWire getSteel() {
            return steel;
        }
        public void setSteel(SteelWire steel) {
            this.steel = steel;
        }
    }

      (6),定义钢丝类

    package pattern.prototype;
    
    import java.io.Serializable;
    
    /**
     * 手刹组件;钢丝
     * 电动车手刹需要用到钢丝拉动刹车片才能减速
     * 所以手刹是由钢丝构成
     * @author ningbeibei
     */
    public class SteelWire implements Serializable,ProtoType,Cloneable{
        //钢丝品牌
        public String brand;
        //钢丝最大拉力值
        public int no;
        
        /**
         * 浅克隆方法
         */
        @Override
        public ProtoType getShallowCloneInstance() {
            Object obj=null;
            try {
                obj = super.clone();
                return (Bicycle)obj;
            } catch (CloneNotSupportedException e) {
                System.out.println("不支持克隆");
                return null;
            }
        }
    
        /**
         * 深克隆方法
         * 调用工具类ProtoTypeUtil.getSerializInstance方法复制一个新的对象
         */
        @Override
        public ProtoType getDeepCloneInstance(ProtoType protoType) {
            //调用工具类中的序列化对象方法复制对象
            return ProtoTypeUtil.getSerializInstance(protoType);
        }
    }

      上面代码中都实现三个接口

      Serializable:表明允许这个类被序列化

      ProtoType:自定义接口需要实现浅克隆和深克隆方法

      Cloneable:表明这个类允许被克隆,如果不实现这个接口在克隆时会抛出异常

      在上面的代码中 Bicycle 类中包含了 ParkingBrake 和 Accumulato r类,在 ParkingBrake 类中包含了 SteelWire 类,这样就能充分体现深克隆和浅克隆区别,现在可以直接去测试类中看下区别。

      (6),测试类

    package pattern.prototype;
    
    public class test {
    
        public static void main(String[] args) {
                                                                                
            Bicycle bicycle = new Bicycle(); //创建电动车原型对象                                                               
            ParkingBrake attachment = new ParkingBrake(); //创建手刹对象 
            Accumulator accumulator = new Accumulator(); //创建蓄电池对象
            bicycle.setAccumulator(accumulator); //将蓄电池组装到电动车中
            bicycle.setParking(attachment);    //将手刹添加到电动车中         
            SteelWire steel = new SteelWire();     //钢丝对象
            attachment.setSteel(steel);    //将钢丝对象组装到手刹中
            Bicycle proto = (Bicycle)bicycle.getDeepCloneInstance(bicycle); //深克隆,复制一个新的电动车对象
    //        Bicycle proto = (Bicycle)bicycle.getShallowCloneInstance();  //浅克隆,
            
            System.out.println("电动车"+(proto==bicycle)); 
            System.out.println("电动车手刹"+(proto.getParking()==bicycle.getParking()));
            System.out.println("手刹钢丝"+(proto.getParking().getSteel()==bicycle.getParking().getSteel()));
            System.out.println("电动车蓄电池"+(proto.getAccumulator()==bicycle.getAccumulator()));
        }
    
    }

      深克隆运行结果:都是false说明深克隆出来的对象已经和原对象没有任何联系,修改新的对象也不会影响原来的对象,说明内部手刹钢丝和蓄电池都已经是独立存在的。

       浅克隆运行结果:运行结果不难发现手刹、钢丝、蓄电池都是true,这说明复制的出来对象内部组件引用都指向了原对象,也就是说新对象和老对象内部组件引用都是一个对象,当修改新对象或者原对象时新对象也会修改,这就是浅克隆和深克隆的区别,当然深克隆到底克隆几层这个问题还需要深入探讨。

    5、原型模式优点和缺点

      优点:

      1,当创建的对象实例较为复杂的时候,使用原型模式可以简化对象的创建过程。
      2,扩展性好,由于写原型模式的时候使用了抽象原型类,在客户端进行编程的时候可以将具体的原型类通过配置进行读取。
      3,可以使用深度克隆来保存对象的状态,使用原型模式进行复制。当你需要恢复到某一时刻就直接跳到。比如我们的idea种就有历史版本。

      缺点:

      1,需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的里面,当对已有的类经行改造时需要修改源代码,违背了开闭原则。

      2,在实现深克隆的时需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用的时候,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现相对麻烦。

    6、原型模式使用场景

      1,创建对象成本比较大,比如初始化要很长时间的,占用太多CPU的,新对象可以通过复制已有的对象获得的,如果是相似的对象,则可以对其成员变量稍作修改。
      2,系统要保存对象状态的,而对象的状态改变很小。
      3,需要避免使用分层次的工厂类来创建分层次的对象,并且类的对象就只用一个或很少的组合状态。

    7、总结

      创建型的设计模式,除开建造者模式基本学习完毕。不过是基础的学习。还没有正式的运用!在写代码的时候需要取考虑使用这种设计模式与否。学而不用存粹浪费时间。其次,创建型的设计模式是基础,需要好好理解这些模式才能够理解其他的结构型以及行为型的设计模式。  

  • 相关阅读:
    暑假第五周报告
    读《大道至简》有感
    暑假第四周报告
    暑假第三周报告
    暑假第二周报告
    暑假第一周报告
    对15号夏壹队的TD信息通——teamfinal的使用体验
    Django易混淆问题
    MySQL常见问题
    Django框架的理解和使用的常见问题
  • 原文地址:https://www.cnblogs.com/ningbeibei/p/14649080.html
Copyright © 2020-2023  润新知