设计模式(四)(适配器模式、外观模式)
八:适配器模式
适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
主要解决:主要解决在软件系统中,常常要将一些”现存的对象”放到新的环境中,而新环境要求的接口是现对象不能满足的。
何时使用: 1、系统需要使用现有的类,而此类的接口不符合系统的需要。 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。 3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)
如何解决:继承或依赖(推荐)。
关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。
应用实例: 1、美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。 2、JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。 3、在 LINUX 上运行 WINDOWS 程序。 4、JAVA 中的 jdbc。
优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。
缺点: 1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。
实现:
首先来一个鸭子接口:
/*
* 鸭子接口
* @author zzf
* @date 2018年10月23日 下午4:40:46
*/
public interface Duck {
public void quack();
public void fly();
}
实现它:
/*
* 绿头鸭子
* @author zzf
* @date 2018年10月23日 下午4:41:38
*/
public class MallardDuck implements Duck{
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("鸭子叫");
}
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("鸭子会飞");
}
}
还有鸡的接口:
/*
* 鸡儿接口
* @author zzf
* @date 2018年10月23日 下午4:43:22
*/
public interface Turkey {
public void gobble();
public void fly();
}
/*
* 野生的火鸡儿
* @author zzf
* @date 2018年10月23日 下午4:44:33
*/
public class WildTurkey implements Turkey{
@Override
public void gobble() {
// TODO Auto-generated method stub
System.out.println("鸡儿叫");
}
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("鸡儿飞");
}
}
现在需要一个被适配者:
/*
* 鸭子的适配器
* @author zzf
* @date 2018年10月23日 下午4:46:44
*/
public class TurkeyAdapter implements Duck{
Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey=turkey;
}
@Override
public void quack() {
// TODO Auto-generated method stub
turkey.gobble();
}
@Override
public void fly() {
// TODO Auto-generated method stub
turkey.fly();
turkey.fly();
turkey.fly();
}
}
测试:
/*
* @author zzf
* @date 2018年10月23日 下午4:48:42
*/
public class DuckTestDrive {
public static void main(String[] args) {
MallardDuck duck=new MallardDuck();//绿头鸭子
WildTurkey turkey=new WildTurkey();//火鸡儿
Duck turkeyAdapter=new TurkeyAdapter(turkey);//鸭子适配器
System.out.println("火鸡儿叫:");
turkey.gobble();
turkey.fly();
System.out.println("绿头鸭子叫:");
Duck(duck);
System.out.println("火鸡儿学鸭子:");
Duck(turkeyAdapter);
}
public static void Duck(Duck duck) {
duck.quack();
duck.fly();
}
}
可以看到鸡儿转鸭子了……
外观模式不只简化了接口,也将客户从组件的子系统中解耦。
外观模式和适配器模式可以包装许多类,但是外观模式的意图是简化接口,而适配器的意图是将接口转换成不同接口。
九:外观模式
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。
何时使用: 1、客户端不需要知道系统内部的复杂联系,整个系统只需提供一个”接待员”即可。 2、定义系统的入口。
如何解决:客户端不与系统耦合,外观类与系统耦合。
关键代码:在客户端和复杂系统之间再加一层,这一次将调用顺序、依赖关系等处理好。
应用实例: 1、去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便。 2、JAVA 的三层开发模式。
优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。
缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
使用场景: 1、为复杂的模块或子系统提供外界访问的模块。 2、子系统相对独立。 3、预防低水平人员带来的风险。
注意事项:在层次化结构中,可以使用外观模式定义系统中每一层的入口。
实现:
/*
* @author zzf
* @date 2018年10月24日 下午1:44:48
*/
public interface Shape {
void draw();
}
/*
* @author zzf
* @date 2018年10月24日 下午1:46:05
*/
public class Square implements Shape{
@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("正方形");
}
}
/*
* @author zzf
* @date 2018年10月24日 下午1:45:16
*/
public class Rectangle implements Shape{
@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("长方形");
}
}
/*
* @author zzf
* @date 2018年10月24日 下午1:46:45
*/
public class Circle implements Shape{
@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("圆形");
}
}
外观类:
/*
* @author zzf
* @date 2018年10月24日 下午1:47:27
*/
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
public void drawCircle() {
circle.draw();
}
public void drawRectangle() {
rectangle.draw();
}
public void drawSquare() {
square.draw();
}
public void draw() {
rectangle.draw();
square.draw();
circle.draw();
}
}
测试类:
/*
* @author zzf
* @date 2018年10月24日 下午1:48:04
*/
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
System.out.println("-----------------------");
shapeMaker.draw();
}
}
要点:
1、当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器。
2、当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。
3、适配器改变接口以符合客户的期望。
4、外观将客户从一个复杂的子系统中解耦。
5、实现一个适配器的复杂度视目标接口大小与复杂度而定。
6、一个子系统可以实现一个以上的外观。
7、适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;而外观将一群对象“包装”起来以简化其接口。
还没有评论,来说两句吧...