Head First 设计模式 读书笔记
设计原则:
-
封装变化:找出应用中需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
-
针对接口编程,而不是针对实现编程
-
多用组合,少用继承(组合:将几个类结合起来使用)
-
为交互对象之间的松耦合设计而努力
-
开放-关闭原则:对扩展开放,对修改关闭
-
依赖倒置原则:依赖抽象而不是依赖具体类
-
最少知识原则:只和你的密友交谈。指在该对象的方法内,只调用如下范围内的方法(即密友的定义)
-
该对象本身
-
被当做方法参数传进来的对象
-
此方法所创建或实例化的对象
-
当前对象的实例变量直接引用的对象
-
缺点:制造出过多的“包装”类,增加复杂性和开发时间,降低运行性能。
-
设计上的体现
-
优先考虑将一个类设置成不变类。
-
尽量降低一个类的访问权限。
-
谨慎使用Serializable。
-
尽量降低成员的访问权限。
-
例子
//不采用最少知识原则。 public float getTemp(){ //从气象站取得温度计(thremometer) Thremometer thremometer = station.getThremomete(); //从温度计取得温度 return thremometer.getTemperature(); }
//采用最少知识原则。 public float getTemp(){ //增加方法,方法中向温度计请求温度 return station.getTemperature(); }
-
好莱坞原则:别调用我们,我们会调用你。(尽量高层次组件调用低层次组件,避免环状依赖。)
1.观察者模式
2.装饰者模式
使用场景:建立有弹性的设计,维持 “对扩展开发,对修改关闭”的开放-关闭原则。(只在最有可能改变的地方应用开放-关闭原则)
特点:
-
所有装饰者都是一个类型
缺点:会建立大量的小类,用于装饰,过度使用,会让程序变得很复杂。比如java.io类库中的大部分类是用来装饰的类,比如BufferedInputStream是用来装饰FileInputStream的。
3.工厂模式
-
所有工厂都是用于封装对象的创建
-
抽象工厂是定义一个产品家族的抽象类型,运用对象组合。对象的创建被实现在工厂接口所暴露出的方法中。
-
工厂方法是创建一个父类,运用子类的继承。对象的创建是由子类实现工厂方法完成的。允许将实例化延迟到子类中进行。
-
抽象工厂用来创建一个产品家族,工厂方法只用来实现具体产品。比如对于一个披萨产品,可以用抽象工厂抽象出一个披萨整体工厂,用工厂方法实现每个产品比如芝士披萨、海鲜披萨、披萨包装盒、披萨刀叉等各个产品。抽象工厂是多个工厂的集合,
4.单例模式
唯一目的:确保类只有一个并且提供全局访问点。
构成:私有构造器+一个静态方法+一个静态变量
用于某些只需要一个的对象,比如线程池、缓存、日志对象、充当打印机、显卡等驱动程序的对象。相对于全局变量程序开始就必须创建(部分jvm实现不同)来说,可以在需要时创建。(延迟实例化)
-
懒汉模式:类产生的时候就创建好实例
class Singleton { // 私有的构造函数,保证外类不能实例化本类 private Singleton() {} // 自己创建一个类的实例化 private static Singleton singleton; // 创建一个get方法,返回一个实例s public static Singleton getInstance(){ //判断singleton是否为null,如果为null,即判定需要实例化 //双重检查加锁 if (singleton == null) { syschronized(Singleton.class){ if (singleton == null){ singleton = new Singleton(); } } } return singleton; } }
-
饿汉模式:需要用到创建实例了程序再去创建实例
public class Singleton { //构造方法私有化,不允许外部直接创建对象 private Singleton(){} //创建类的唯一实例,使用private static修饰 private static Singleton instance=new Singleton(); //提供一个获取实例的方法,使用public static修饰 public static Singleton getInstance() { return instance; } }
注意:如果你有多个类加载器还使用了单例模式,可能会导致单例失效而产生多个实例。因为不同类加载器可能会加载同一个类,导致单例类被加载多次,产生多个单例。
5.命令模式
-
可以通过宏命令一次调用多个命令,并支持撤销。宏命令相比于在一个excute()中调用另一个excute()方法,可以更加灵活地增加或减少所需执行的命令且更优雅。
-
可以不指定接受者而是直接实现请求。但这样的话解耦程度较低。
6.适配器模式
-
对象适配器
-
类适配器(多重继承,不适合Java)
-
外观是为了简化接口,适配器是为了将一个接口转换成另一个
7.外观模式
提供一个统一的接口,用来访问子系统中的一群接口,让子系统更容易使用。.
8.模板模式
-
定义:在一个方法中定义一个算法的骨架,将某些步骤延迟到子类中实现。
-
某些步骤是必须实现的,比如茶叶/咖啡冲水,就用抽象方法。某些步骤可以选择实现,就用钩子(在抽象类中不实现功能,子类可以选择是否覆盖它)。
-
为了防止子类改变模板方法,可以将模板方法声明为final
9.迭代器模式
-
定义:能顺序访问一个聚合对象中的各个元素,又不暴露其内部表示