设计模式之禅读书笔记—创建类模式
23种设计模式可以分为三大类.创建类,结构类,行为类.
创建类模式:(都能够提供对象的创建和管理职责)
-
单例模式:保持在内存中只有一个对象
-
工厂方法模式
-
抽象工厂模式
-
建造者模式
-
原型模式:通过复制的方式产生一个新的对象
单例模式
定义:确保单例类只有一个实例,而且自行实例化并向整个系统提供这个实例.
优点:
-
减少内存开支,特别是一个对象需要频繁创建,销毁时.
-
由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决
-
避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作.
-
可以在系统设置全局的访问点,优化和共享资源访问.
缺点
-
一般没有接口,不易扩展
-
对测试不利
-
与单一职责原则有冲突.
工厂方法模式
定义: 定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类
优点:
-
屏蔽产品类.产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不用发生变化.
-
典型的解耦框架.高层模块只需知道产品的抽象类,其他实现类都不用关心,符合迪米特法则,也符合依赖倒置原则,只依赖产品类的抽象.当然符合里氏替换原则原则,使用产品子类替换产品父类.
扩展:
-
简单工厂模式(静态工厂模式)
-
多个工厂类:在遇到初始化一个对象很费精力的时候,所有的产品类都放到一个工厂方法中进行初始化会使代码结构不清晰.此时可以针对每个产品都对应一个创建者.类图:
-
替代单例模式(通过注解生成唯一对象)
-
延迟初始化.对象被消费完毕后,并不立刻释放,工厂类保持其初始化状态,等待再次被使用.类图:
抽象工厂模式
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无须指定他们的具体类.
说明:抽象工厂模式是工厂方法模式的升级版,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式.
优点:
-
封装性.每个产品的实现类,它关心的是接口,抽象.它不关心对象是如何创建出来.只要知道工厂类是谁,就能创建出一个需要的对象.
-
产品族内的约束为非公开状态.具体的产品族内的约束是在工厂内实现的.
缺点:
产品族扩展非常困难.例如:要增加一个产品C,也就是说产品家族由原来的两个增加到3个,这就要在抽象类AbstractCreator增加一个方法createProductC(),然后两个实现类都要修改.所以严重违反了开闭原则.
使用场景:
一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以用抽象工厂模式.
注意事项:
产品组扩展比较困难(如:增加产品C.D...),产品等级是非常容易扩展的,增加一个产品等级,只要增加一个工厂类负责新增加出来的产品生产任务即可.也就是说横向扩展容易,纵向扩展困难.
建造者模式/生成器模式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.
优点:
-
封装性:可以使客户端不必知道产品内部组成的细节.
-
建造者独立,容易扩展
-
便于控制细节风险
使用场景:
-
相同方法,不同的执行顺序,产生不同的事件结果时
-
多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同
-
在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时,可以采用建造者模式封装该对象的创建过程.
原型模式(实现Cloneable接口)
定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象..
优点:
-
性能优良:原型模式是在内存二进制流的拷贝,比直接new一个对象性能好很多.
-
逃避构造函数的约束.直接在内存中拷贝,构造函数是不会执行的.
浅拷贝:Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址.
深拷贝:主要final修饰的变量是无法进行深拷贝的
public class Thing implements Cloneable{ // private ArrayList<String> arrayList = new ArrayList<String>();@Override public Thing clone(){ Thing thing=null; try { thing = (Thing)super.clone(); thing.arrayList = (ArrayList<String>)this.arrayList.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return thing; } }