设计模式之-----原型模式
1. 设计模式的类型
- 创建型模式
- 单例模式(Singleton)
- 工厂模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
- 原型模式(Prototype)
- 建造者模式(Builder)
- 结构型模式
- 适配器模式(Adapter)
- 桥接模式(Bridge)
- 组合模式(Composite)
- 装饰器模式(Decorator)
- 外观模式(Facade)
- 享元模式(Flyweight)
- 代理模式(Proxy)
- 行为型模式
- 责任链模式(Chain Of Responsibility)
- 命令模式(Command)
- 解释器模式(Interpreter)
- 迭代器模式(Iterator)
- 中介者模式(Mediator)
- 备忘录模式(Memento)
- 观察者模式(Observer)
- 状态模式(State)
- 策略模式(Strategy)
- 模板模式(Template Method)
- 访问者模式(Visitor)
设计模式的六大原则
- 开闭原则
- 开闭原则的意思是:对扩展开放,对修改关闭。在程序进行拓展的时候,不能修改原有的代码,实现一个热拔插的效果。简而言之,是为了使程序扩展性更好,易于维护和升级,想要达到这样的效果,我们需要使用接口和抽象类。
- 里氏代换原则
- 里氏代换原则是面向对象设计的基本准则之一,里氏代换意思是:任何基类出现的地方,子类一定可以出现,只有当派生类可以替换掉基类,且软件单位的功能不受影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充,实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体体现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
- 依赖倒转原则
- 这个原则是开闭原则的基础,具体内容是,针对接口编程,依赖于抽象而不依赖于具体。
- 接口隔离原则
- 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好,它还有另外一个意思是:降低类之间的契合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
- 迪米特原则、又称最少知道原则
- 迪米特原则是指:一个实体应当尽量少与其他实体之间发生相互作用,使得系统功能模块相对独立。
- 合成复用原则
- 合成复用原则是指:尽量使用合成/聚合得方式,而不是使用继承。
原型模式
简介
- 原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现一个原型接口Cloneable并且重写clone方法,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如一个对象需要在一个高代价的数据库操作之后被创建,我们可以缓存这个对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库的调用。
优点
- 性能提高,原型模式是在内存中通过二进制流的形式进行拷贝,要比直接new一个对象性能好的多,特别是在循环体内产生大量的对象,原型模式能更好的体现它的优点
- 逃避构造函数的约束,这一点即是优点也是缺点,直接在内存中进行拷贝,构造函数是不会执行的,优点是减少了约束,但缺点也是减少了约束。
缺点
- 必须实现Cloneable接口重写clone方法。
- 配置克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
场景
- 资源优化场景。
- 类初始化需要消耗非常多的资源,这个资源包括数据,硬件资源等。
- 性能和安全要求的场景
- 通过new产生一个对象需要非常繁琐的数据准备或访问权限,可以使用原型模式。
- 一个对象多个修改者的场景。
- 一个对象需要提供给其他对象访问,并且各个调用者可能都修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
- 在实际项目中,原型模式一般很少单独使用,一般情况下都是和工厂模式进行搭配使用。通过clone方法创建一个对象,然后由工厂模式提供给调用者。
分类
- 原型模式分为两种:
- 浅克隆
- 当一个对象在使用浅克隆模式进行对象的创建的时候,这个对象如果引用了其他对象,克隆的对象和原对象引用的其他对象在堆内存中只存在一份。如果原对象修改了这个引用对象的值,克隆的对象的引用对象的值也会进行修改。
- 深克隆
- 当一个对象在使用深克隆模式进行对象创建的时候,这个对象如果引用了其他对象,引用的对象也会进行克隆,深克隆的实现方式分为两种:
- 对象和对象中的引用对象都实现Cloneable接口,并且重写clone方法。
- 使用序列化和反序列化实现对象的深克隆。
- 当一个对象在使用深克隆模式进行对象创建的时候,这个对象如果引用了其他对象,引用的对象也会进行克隆,深克隆的实现方式分为两种:
- 浅克隆
实现
-
关键代码:
-
实现克隆操作,在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()方法非常繁琐,特别是对于一些有连续引用的对象更是如此。