简单聊聊设计模式之原型模式

设计模式之-----原型模式

1. 设计模式的类型

  • 创建型模式
    1. 单例模式(Singleton)
    2. 工厂模式(Factory Method)
    3. 抽象工厂模式(Abstract Factory)
    4. 原型模式(Prototype)
    5. 建造者模式(Builder)
  • 结构型模式
    1. 适配器模式(Adapter)
    2. 桥接模式(Bridge)
    3. 组合模式(Composite)
    4. 装饰器模式(Decorator)
    5. 外观模式(Facade)
    6. 享元模式(Flyweight)
    7. 代理模式(Proxy)
  • 行为型模式
    1. 责任链模式(Chain Of Responsibility)
    2. 命令模式(Command)
    3. 解释器模式(Interpreter)
    4. 迭代器模式(Iterator)
    5. 中介者模式(Mediator)
    6. 备忘录模式(Memento)
    7. 观察者模式(Observer)
    8. 状态模式(State)
    9. 策略模式(Strategy)
    10. 模板模式(Template Method)
    11. 访问者模式(Visitor)

设计模式的六大原则

  1. 开闭原则
    • 开闭原则的意思是:对扩展开放,对修改关闭。在程序进行拓展的时候,不能修改原有的代码,实现一个热拔插的效果。简而言之,是为了使程序扩展性更好,易于维护和升级,想要达到这样的效果,我们需要使用接口和抽象类。
  2. 里氏代换原则
    • 里氏代换原则是面向对象设计的基本准则之一,里氏代换意思是:任何基类出现的地方,子类一定可以出现,只有当派生类可以替换掉基类,且软件单位的功能不受影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充,实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体体现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
  3. 依赖倒转原则
    • 这个原则是开闭原则的基础,具体内容是,针对接口编程,依赖于抽象而不依赖于具体。
  4. 接口隔离原则
    • 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好,它还有另外一个意思是:降低类之间的契合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
  5. 迪米特原则、又称最少知道原则
    • 迪米特原则是指:一个实体应当尽量少与其他实体之间发生相互作用,使得系统功能模块相对独立。
  6. 合成复用原则
    • 合成复用原则是指:尽量使用合成/聚合得方式,而不是使用继承。

原型模式

简介

  • 原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现一个原型接口Cloneable并且重写clone方法,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如一个对象需要在一个高代价的数据库操作之后被创建,我们可以缓存这个对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库的调用。

优点

  • 性能提高,原型模式是在内存中通过二进制流的形式进行拷贝,要比直接new一个对象性能好的多,特别是在循环体内产生大量的对象,原型模式能更好的体现它的优点
  • 逃避构造函数的约束,这一点即是优点也是缺点,直接在内存中进行拷贝,构造函数是不会执行的,优点是减少了约束,但缺点也是减少了约束。

缺点

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

场景

  • 资源优化场景。
  • 类初始化需要消耗非常多的资源,这个资源包括数据,硬件资源等。
  • 性能和安全要求的场景
  • 通过new产生一个对象需要非常繁琐的数据准备或访问权限,可以使用原型模式。
  • 一个对象多个修改者的场景。
  • 一个对象需要提供给其他对象访问,并且各个调用者可能都修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
  • 在实际项目中,原型模式一般很少单独使用,一般情况下都是和工厂模式进行搭配使用。通过clone方法创建一个对象,然后由工厂模式提供给调用者。

分类

  • 原型模式分为两种:
    • 浅克隆
      • 当一个对象在使用浅克隆模式进行对象的创建的时候,这个对象如果引用了其他对象,克隆的对象和原对象引用的其他对象在堆内存中只存在一份。如果原对象修改了这个引用对象的值,克隆的对象的引用对象的值也会进行修改。
    • 深克隆
      • 当一个对象在使用深克隆模式进行对象创建的时候,这个对象如果引用了其他对象,引用的对象也会进行克隆,深克隆的实现方式分为两种:
        1. 对象和对象中的引用对象都实现Cloneable接口,并且重写clone方法。
        2. 使用序列化和反序列化实现对象的深克隆。

实现

  • 关键代码:

    • 实现克隆操作,在java中继承Cloneable接口,重写clone方法。

    • 浅克隆

      package com.hoperun.design;
      import lombok.AllArgsConstructor;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      import lombok.ToString;
      
        /**
      
      - @ClassName ShallowClone
      - @Description: TODO   浅克隆
      - @Author qywang
      - @Date 2020/7/12
      - @Version V1.0
      **/
      @Data
      @AllArgsConstructor
      @ToString
      @NoArgsConstructor
      public class ShallowClone implements Cloneable{
        
        private String username;
        
        private int age;
        
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
        
        public static void main(String[] args) throws CloneNotSupportedException {
        
            ShallowClone shallowClone = new ShallowClone("张无忌",23);
            ShallowClone clone = (ShallowClone)shallowClone.clone();
            clone.setAge(24);
            clone.setUsername("赵敏");
            System.out.println(shallowClone);
            System.out.println(clone);
        
        }
      }
      /**
      运行结果
      ShallowClone(username=张无忌, age=23)
      ShallowClone(username=赵敏, age=24)
      */
      
    • 深克隆

      • 引用对象实现Cloneable接口重写clone()方法实现深克隆

         package com.hoperun.design;
          
          import lombok.AllArgsConstructor;
          import lombok.Data;
          import lombok.NoArgsConstructor;
          import lombok.ToString;
          
          /**
           * @ClassName Father
           * @Description: TODO
           * @Author qywang
           * @Date 2020/7/12
           * @Version V1.0
           **/
          @Data
          @NoArgsConstructor
          @ToString
          @AllArgsConstructor
          public class Father implements Cloneable {
          
              private String username;
          
              private int age;
          
              @Override
              public Object clone() throws CloneNotSupportedException {
                  return super.clone();
              }
          }
          
          
          package com.hoperun.design;
          
          import lombok.AllArgsConstructor;
          import lombok.Data;
          import lombok.NoArgsConstructor;
          import lombok.ToString;
          
          /**
           * @ClassName ShallowClone
           * @Description: TODO   深克隆
           * @Author qywang
           * @Date 2020/7/12
           * @Version V1.0
           **/
          @Data
          @AllArgsConstructor
          @ToString
          @NoArgsConstructor
          public class DeepClone implements Cloneable {
          
              private String username;
          
              private int age;
          
              private Father father;
          
              @Override
              public Object clone() throws CloneNotSupportedException {
                  DeepClone clone = (DeepClone) super.clone();
                  clone.father = (Father) clone.getFather().clone();
                  return clone;
              }
          
              public static void main(String[] args) throws CloneNotSupportedException {
          
                  Father father = new Father("张翠山", 45);
                  DeepClone deepClone = new DeepClone("张无忌", 23, father);
                  DeepClone clone = (DeepClone) deepClone.clone();
                  clone.setAge(24);
                  clone.setUsername("赵敏");
                  clone.getFather().setAge(46);
                  clone.getFather().setUsername("汝南王");
                  System.out.println(deepClone);
                  System.out.println(clone);
          
              }
          }
          
          /**
          运行结果
          DeepClone(username=张无忌, age=23, father=Father(username=张翠山, age=45))
          DeepClone(username=赵敏, age=24, father=Father(username=汝南王, age=46))
          */
        
      • 序列化实现原型模式的深克隆

        package com.hoperun.design.Serializable;
        
        import lombok.AllArgsConstructor;
        import lombok.Data;
        import lombok.NoArgsConstructor;
        import lombok.ToString;
        
        import java.io.Serializable;
        
        /**
         * @ClassName Father
         * @Description: TODO
         * @Author qywang
         * @Date 2020/7/12
         * @Version V1.0
         **/
        @Data
        @NoArgsConstructor
        @ToString
        @AllArgsConstructor
        public class Father implements Serializable {
        
            private String username;
        
            private int age;
        
        }
        
        package com.hoperun.design.Serializable;
        
        import lombok.AllArgsConstructor;
        import lombok.Data;
        import lombok.NoArgsConstructor;
        import lombok.ToString;
        
        import java.io.*;
        
        /**
         * @ClassName ShallowClone
         * @Description: TODO   深克隆
         * @Author qywang
         * @Date 2020/7/12
         * @Version V1.0
         **/
        @Data
        @AllArgsConstructor
        @ToString
        @NoArgsConstructor
        public class DeepClone implements Serializable {
        
            private String username;
        
            private int age;
        
            private Father father;
        
            public Object deepClone() throws Exception{
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream obj = new ObjectOutputStream(bos);
        
                obj.writeObject(this);
                ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bis);
                return ois.readObject();
            }
        
        
            public static void main(String[] args) throws Exception {
        
                Father father = new Father("张翠山", 45);
                DeepClone deepClone = new DeepClone("张无忌", 23, father);
                DeepClone clone = (DeepClone)deepClone.deepClone();
        
                clone.setAge(24);
                clone.setUsername("赵敏");
                clone.getFather().setAge(46);
                clone.getFather().setUsername("汝南王");
                System.out.println(deepClone);
                System.out.println(clone);
        
            }
        }
        /**
        运行结果
        DeepClone(username=张无忌, age=23, father=Father(username=张翠山, age=45))
        DeepClone(username=赵敏, age=24, father=Father(username=汝南王, age=46))
        */
        

注意事项

  • 对于深克隆来说,通过实现Serializable接口通过序列化进行深克隆在工作中使用更多一点。对于深克隆如果要通过实现Cloneable接口重写clone()方法非常繁琐,特别是对于一些有连续引用的对象更是如此。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值