适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。
如果目标接口发生改变,适配器可以将改变的部分封装起来,客户就不必为了应对不同的接口而每次跟着修改。
客户通过目标接口调用适配器的方法对适配器发出请求。
适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口。
(客户表面上看到的是目标接口,实际上通过适配器,在调用目标接口的方法时,将实际的所有请求都委托给被适配者。)
实现一个适配器所需要进行的工作,和目标接口的大小成正比。要实现一个很大的目标接口,那适配器就有很多工作要做。
上图指的是对象适配器。它使用组合,不仅可以适配某个类,也可以适配该类的任何子类。
还有一种适配器是类适配器。它不是使用组合来适配被适配者,而是继承被适配者和目标类。因为需要多继承才能够实现它,但是java不支持多继承。
需求实例:将火鸡包装成鸭子(可以理解为:谁(被适配者)将成为谁(目标接口))。
1、目标接口
//目标接口
public interface Duck {
public void quack();
public void fly();
}
//目标接口实现类
public class MallDuck implements Duck {
public void quack() {
System.out.println("Quack");
}
public void fly() {
System.out.println("Fly");
}
}
2、被适配者接口
//被适配者接口
public interface Turkey {
public void gobble();
public void fly();
}
//被适配者接口实现类
public class WildTurkey implements Turkey {
public void gobble() {
System.out.println("Gobble");
}
public void fly() {
System.out.println(" torkey Fly");
}
}
3、适配器:让火鸡冒充鸭子对象
//需要实现想转换的目标接口类型,也就是客户想看到的接口
public class TurkeyAdapter implements Duck {
//利用组合,被适配者引用
Turkey turkey;
//初始化 被适配者的引用
public TurkeyAdapter(Turkey turkey){
this.turkey=turkey;
}
//实现接口方法
public void quack() {
//将实际的方法调用委托给被适配者
turkey.gobble();
}
public void fly() {
turkey.fly();
}
}
5、测试实例:
public class DuckTestDrive {
public static void main(String[] args) {
//接口实现类对象
MallDuck duck=new MallDuck();
//被适配者对象
WildTurkey turkey=new WildTurkey();
//适配器:将火鸡包装进适配器,让其看起来像只鸭子
Duck turkeyAdapter=new TurkeyAdapter(turkey);
duckTest(turkeyAdapter);
}
static void duckTest(Duck duck){
duck.fly();
duck.quack();
}
}
//结果
torkey Fly
//表面看是鸭子,其实是火鸡
Gobble
外观模式
外观模式提供一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更加容易使用。
外观模式的意图是要提供一个简单的接口,好让子系统更易于使用。
需求实例:观看电影的过程,需要调节灯光暗度、放下屏幕、打开投影仪、打开DVD、播放影片等一系列流程。
1、将这些流程看做是一个子系统,提供一个对外的接口执行这些流程,而不是单独执行每一个操作。(如果要单独使用也是可以的)
//使用外观模式,创建一个接口简单而统一的类,用来包装子系统中一个或多个复杂的类。
public class HomeThreaterFacade {
//使用组合,用到的所有子系统组件到包括进来
DvdPlayer dvd;
Projector projector;
TheaterLights lights;
MovenScreen screen;
public HomeThreaterFacade(DvdPlayer dvd,Projector projector,TheaterLights lights,MovenScreen screen){
this.dvd=dvd;
this.projector=projector;
this.lights=lights;
this.screen=screen;
}
//提供一个对外的同一接口
public void watchMovie(String movie){
lights.dim(10);
screen.down();
projector.on();
dvd.on();
}
}
2、测试
public class HomeDrive {
DvdPlayer dvd=new DvdPlayer();
Projector projector=new Projector();
TheaterLights lights=new TheaterLights();
MovenScreen screen=new MovenScreen();
//根据子系统所有的组件来实例化外观
HomeThreaterFacade home=new HomeThreaterFacade(dvd,projector,lights,screen);
//直接调用接口方法
home.watchMovie();
}
设计原则:最少知识原则(得墨忒耳法则):减少对象之间的交互,只留下几个重要的对象。
不要让太多的类耦合在一起,免得修改系统中一部分,会影响其他部分。
这个原则提供了一些方针:
就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:
1、该对象本身
2、被当做方法的参数而传递进来的对象
3、此方法所创建或实例化的任何对象
4、对象的任何组件
注意:如果某对象是调用其他的方法的返回结果,那不要调用该返回对象的方法。
//违反最少知识原则
public float getTemp(){
//先返回一个对象,再调用该对象的方法
return station.getThermomter().getTemperature();
}
//没有违反原则
public int getIntTemp(){
//返回一个对象
Thermoment thermoment=station.getThermomter();
//将该对象作为参数传递
return getTempHelper(thermoment);
}
public int getTempHelper(Thermoment thermoment){
//可以调用作为参数传递进来的对象的方法
return thermoment.getTemperature();
}
适配器将一个对象包装起来以改变其接口;
装饰者将一个对象包装起来以增加新的行为和责任;
外观将一群对象包装起来以简化其接口。