简明 适配器模式(4.1)
来源:互联网 发布:晶体非晶体区别 知乎 编辑:程序博客网 时间:2024/06/03 19:46
★适配器模式(adapter pattern),又名包装器(Wrapper),是一种“改装/伪装式”委派模式。
问题描述:假定接口Being(生命) 有抽象方法eat()、move (),实现类有狗/Dog等等;
现有 (第三方) 已经存在的鸟/Bird类,但是Bird拥有的方法头/接口不相同,如eat()和fly();
再比如,程序员/Client希望将汽车/Car、机器人/Robot……(其他一些你可以想象出来的东西)也“作为”Being来统一处理,(这里故意地使)它们拥有的方法头/接口各不相同,例如Car有加油/refuel()方法等。
由于希望将Bird、Car、Robot……改装或伪装成为Being以便统一处理,可以将“已经存在的类”再次包装一下,使其包装类BirdWrapper、CarWrapper、RobotWrapper等等作为Being的子类。外界自然地将BirdWrapper等作为Being,从而间接地使用遗留的Bird、Car、Robot……等类。
package delegate.adapter;public class Client{ public static void main(String args[]){Being b= new BirdWrapper();b.eat();b.move();}}容易想象,BirdWrapper改写Being的eat()、run()方法时,将消息转发给被包装的类Bird的对应方法。再例如CarWrapper的eat()实现将调用Car的加油/refuel()方法。
5.3.1 转发的方式
包装类BirdWrapper与遗留类的Bird,既可以是Is-A的继承关系,也可以Has-A的组合关系。
图 5‑4 适配器XxxWrapper
建议:同学们看到这里,自己看图说话——编写出代码。
1. Is_A型适配器
当BirdWrapper是一个Bird,意味着Being和Bird均为适配器类BirdWrapper的父类型。如果遗留的Bird是一个类,Being必须设计为一个Java接口。package delegate.adapter;public class Bird{//来自第三方的或不可修改的类 public void eat(){System.out.println("Bird.eat()");}public void fly(){System.out.println("Bird.fly()");}}package delegate.adapter;public class BirdWrapper extends Bird implements Being {@Override public void eat(){ //此方法可以省略super.eat();}@Override public void run(){super.fly(); // super.可以省略}}
Is-A型适配器,在《设计模式》/[GoF]中叫做类适配器。
(语法方面)由于采用继承关系,要求Bird类不得为final类——否则无法继承、Bird与Being不得同时为类——Java不支持类的多继承。
现有类Bird的方法体是我们需要的,BirdWrapper可以使用改进语义的override——在调用super.eat()的基础上添加型的代码。
思考题:假设Being有public abstract void say(),编写BirdWrapper时你需要考虑什么?添加一个被匹配类没有提供的方法?退化继承问题?
被适配的类Bird应该是一个具体的类。假设Bird有各种子类如麻雀、鸽子等,BirdWrapper将与麻雀、鸽子同等地位,此时Is-A型适配器无法适配麻雀、鸽子,这时需要使用Has-A型适配器。
2. Has-A型适配器package delegate.adapter;<span style="font-family: Arial, Helvetica, sans-serif;">//来自第三方的或不可修改的类</span>public interface Robot{ public void battery();//电池充电 public void move();}package delegate.adapter;public class RobotWrapper implements Being{ private Robot r; public RobotWrapper(){ //任一创建对象的模式 } @Override public void eat(){r.battery();//}@Override public void run(){r.move();}}
Has-A型适配器,在《设计模式》中叫做对象适配器。由于采用委派关系,被适配的类如Robot可以是一个Java接口或抽象类,Robot拥有自己的类层次。
在[2.1.1空方法的作用]中,介绍了一种伪适配器——JDK中各种窗口控件适配器。值得注意的是,伪适配器模式中,所涉及的各个类本身构成类层次;而适配器模式中,被适配者通过适配器“伪装”成目标类型(Being),并不是目标类型的子类型。JDK中各种窗口控件适配器从意图到结构都和适配器模式无关。
双向适配器:对于上图中的Being和Robot,有人希望把所有的Robot都作为Being,而有人希望把所有的Being都作为Robot,于是出现了双向适配器如DoubleWrapper。
- 适配器模式仅用于复用第三方工具类的情形。如果是自己设计的类Robot,不应该将分析阶段得出的结论——它不是Being,由于代码复用的想法而将Robot再伪装成Being。
- 当然,你作为第三方工具类的提供者,你的用户希望的接口不是你能够了解的。你的类 “可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作”——因为用户可以编写适配器。
- 简明 适配器模式(4.1)
- 4.1适配器模式(ADAPTER)
- 适配器及适配器模式
- 适配器及适配器模式
- 适配器模式(类适配器)
- 适配器模式(默认适配器)
- 适配器模式(对象适配器)
- 适配器模式-类适配器
- 适配器模式-对象适配器
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 添加 centos 右键 terminal
- 用WebCollector制作的博客推送网站
- libusb的使用教程和例子
- 『ANDROID』AsyncTask的使用注意事项
- 借用PortAudio采集和播放音频,实现双路混音器
- 简明 适配器模式(4.1)
- Java 传统桥接模式
- [编程语言] 堆和栈的全面总结
- 数据结构之快排
- 真正的装饰模式(4.4)
- Codeforces Round #264 (Div. 2) B. Caisa and Pylons
- Codeforces Round #170 (Div. 2) B. New Problem
- Implementing the Raytracing Algorithm(primary ray& shadow ray)
- Need to look