七、适配器模式
1. 定义
适配器模式:将一个类的接口,装换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
2. UML类图
说明:
1、客户看到的是目标接口。
2、适配器与被适配者组合。
3、适配器实现目标接口。
4、所有的请求都委托给配适配者。
装饰者和适配器模式对比
- 适配器
- 装饰者
说明:
1、适配器的好处是,允许客户使用行的库和子集合,无须“改变”代码,由适配器负责装换(装饰者同样也可以让“新行为”加入类中,无须修改现有代码)。
2、适配器“一定会”进行接口转换(装饰者的工作是扩展包装对象的行为或责任)。
外观模式
定义
外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更加容易使用。例子:
HomeTheaterFacade 类(高层接口)
public class HomeTheaterFacade {
Amplifier amp;
Tuner tuner;
DvdPlayer dvd;
CdPlayer cd;
Projector projector;
TheaterLights lights;
Screen screen;
PopcornPopper popper;
public HomeTheaterFacade(Amplifier amp,
Tuner tuner,
DvdPlayer dvd,
CdPlayer cd,
Projector projector,
Screen screen,
TheaterLights lights,
PopcornPopper popper) {
this.amp = amp;
this.tuner = tuner;
this.dvd = dvd;
this.cd = cd;
this.projector = projector;
this.screen = screen;
this.lights = lights;
this.popper = popper;
}
public void watchMovie(String movie) {
System.out.println("Get ready to watch a movie...");
popper.on();
popper.pop();
lights.dim(10);
screen.down();
projector.on();
projector.wideScreenMode();
amp.on();
amp.setDvd(dvd);
amp.setSurroundSound();
amp.setVolume(5);
dvd.on();
dvd.play(movie);
}
public void endMovie() {
System.out.println("Shutting movie theater down...");
popper.off();
lights.on();
screen.up();
projector.off();
amp.off();
dvd.stop();
dvd.eject();
dvd.off();
}
public void listenToCd(String cdTitle) {
System.out.println("Get ready for an audiopile experence...");
lights.on();
amp.on();
amp.setVolume(5);
amp.setCd(cd);
amp.setStereoSound();
cd.on();
cd.play(cdTitle);
}
public void endCd() {
System.out.println("Shutting down CD...");
amp.off();
amp.setCd(cd);
cd.eject();
cd.off();
}
public void listenToRadio(double frequency) {
System.out.println("Tuning in the airwaves...");
tuner.on();
tuner.setFrequency(frequency);
amp.on();
amp.setVolume(5);
amp.setTuner(tuner);
}
public void endRadio() {
System.out.println("Shutting down the tuner...");
tuner.off();
amp.off();
}
}
Amplifier类(高层接口需要包装的众多子类之一)
public class Amplifier {
String description;
Tuner tuner;
DvdPlayer dvd;
CdPlayer cd;
public Amplifier(String description) {
this.description = description;
}
public void on() {
System.out.println(description + " on");
}
public void off() {
System.out.println(description + " off");
}
public void setStereoSound() {
System.out.println(description + " stereo mode on");
}
public void setSurroundSound() {
System.out.println(description + " surround sound on (5 speakers, 1 subwoofer)");
}
public void setVolume(int level) {
System.out.println(description + " setting volume to " + level);
}
public void setTuner(Tuner tuner) {
System.out.println(description + " setting tuner to " + dvd);
this.tuner = tuner;
}
public void setDvd(DvdPlayer dvd) {
System.out.println(description + " setting DVD player to " + dvd);
this.dvd = dvd;
}
public void setCd(CdPlayer cd) {
System.out.println(description + " setting CD player to " + cd);
this.cd = cd;
}
public String toString() {
return description;
}
}
测试类
public class HomeTheaterTestDrive {
public static void main(String[] args) {
Amplifier amp = new Amplifier("Top-O-Line Amplifier");
Tuner tuner = new Tuner("Top-O-Line AM/FM Tuner", amp);
DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD Player", amp);
CdPlayer cd = new CdPlayer("Top-O-Line CD Player", amp);
Projector projector = new Projector("Top-O-Line Projector", dvd);
TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
Screen screen = new Screen("Theater Screen");
PopcornPopper popper = new PopcornPopper("Popcorn Popper");
HomeTheaterFacade homeTheater = new HomeTheaterFacade(amp, tuner, dvd, cd,
projector, screen, lights, popper);
homeTheater.watchMovie("Raiders of the Lost Ark");
homeTheater.endMovie();
}
}
外观不只是简化了接口,也将客户从组件的子系统中解耦。
外观和适配器可以包装很多类,但是外观的意图是简化接口,而适配器的意图是将接口转换成不同的接口。
- 要点
1、当需要使用一个现有的类而其它接口并不符合你的需要时,就使用适配器。
2、当需要简化并统一一个很大的接口或者一群复杂的接口的时候,使用外观模式。
3、适配器改变接口以符合客户的期望。
4、外观将客户从一个复杂的子系统中解耦。
5、实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂程度而定。
6、实现一个外观,需要将子系统组合进外观中,而将工作委托给子系统执行。
7、Java中只存在对象适配器。
8、可以为一个子系统实现一个以上的外观。
9、适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;而外观将一群对象“包装”起来以简化其接口。
说明:以上智慧参考于HeadFirst书籍,如有必要,请参考原书籍。