设计模式读书笔记(六)

"Head First 设计模式第七章"

Posted by jhljx on January 29, 2018

目录

1. 适配器模式

适配器模式

适配器工作起来就像一个中间人,它将客户所发出的请求转换成厂商类能理解的请求。

客户使用适配器的过程如下:

  • 客户通过目标接口调用适配器的方法对适配器发出请求
  • 适配器使用被适配器者接口把请求转换成被适配器者的一个或多个调用接口
  • 客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用

适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

需要明白,这个模式是如何把客户和接口绑定起来,而不是和实现绑定起来的。我们可以使用数个适配器,每一个都负责转换不同组的后台类。或者,也可以加上新的实现,只要它们遵守目标接口就可以。

适配器实际上有两种:“对象”适配器,“类”适配器

对象适配器使用组合方式将请求传送给被适配者,类适配器使用多重继承Target和Adaptee。

适配器模式的特点:转换接口

装饰者:不改变接口,但加入责任
适配器:将一个接口转换成另一个接口
外观:让接口更简单

外观模式将一个或数个类的复杂的一切都隐藏在背后,只显露出一个干净美好的外观。

有了外观模式,通过实现一个提供更合理的接口的外观类,你可以将一个复杂的子系统变得容易使用

外观模式只是提供你更直接的操作,并未将原来的子系统阻隔起来。如果你需要子系统类的更高层功能,还是可以使用原来的子系统。

外观模式没有“封装”子系统的类,外观只提供简化的接口。所以客户如果觉得有必要,依然可以直接使用子系统的类。这是外观模式一个很好的特征:

  • 提供简化的接口的同时,依然将系统完整的功能暴露出来,以供需要的人使用

可以为一个子系统创建多个外观。

外观不只是简化了接口,也将客户从组建的子系统中解耦。

错误说法:适配器模式与外观模式的差异在于——适配器模式包装了一个类,而外观模式可以代表许多类?

解析:适配器模式也可以适配许多类来提供一个接口让客户编码,外观模式也可以只针对一个拥有复杂接口的类提供简化的接口。

两种模式的差异,不在于它们“包装”了几个类,而是在于它们的意图。适配器模式的意图是,“改变”接口符合客户的期望;而外观模式的意图是,提供子系统的一个简化接口

我们创建了一个接口简化而统一的类,用来包装子系统中一个或多个复杂的类。

外观模式的定义如下:

外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

设计原则——最少知识原则:只和你的密友谈话(减少对象之间的交互)。

当你在设计一个系统时,不管是任何对象,你都要注意它所交互的类有哪些,并注意它和这些类是如何交互的。

注意不良编码习惯:

public float getTemp() {
    return station.getThermometer().getTemperature();
    //违反最少知识原则,因为在此调用的方法属于另一次调用的返回对象
}

这段代码耦合了3个类

如果给station类中加入了getTemperature()方法,可以减少所依赖的类的数目。

public float getTemp() {
    return station.getTemperature();
}

对于最少知识原则,有以下的方针。就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

  • 该对象本身
  • 被当做方法的参数而传递进来的对象
  • 此方法所创建或实例化的任何对象(上面这三条告诉我们,如果某对象是调用其他的方法返回的返回结果,不要调用该对象的方法!)
  • 对象的任何组件(把组件想象成是被实例变量所引用的任何对象,换句话说,把这想象成是“有一个(HAS-A)关系”)

对比以下两段代码,感觉并没有太大区别。

public House {
    WeatherStation station;
    
    // 其他的方法和构造器
    public float getTemp() {
        return station.getThermometer().getTemperature(); 
        //违反最少知识原则
    }
}
public House {
    WeatherStation station;
    
    //其他的方法和构造器
    public float getTemp() {
        Thermometer thermometer = station.getThermometer();
        return getTempHelper(thermometer);
    }
    
    public float getTempHelper(Thermometer thermometer) {
        return thermometer.getTemperature();
        //不违反最小知识原则,但是然并卵...
    }
}