前言
这篇会同时聊到了前边介绍过的代理模式(应该说特指静态代理) 装饰器模式 还有本篇需要讲的 外观模式(Facade)和适配器(Adapter)模式
原因是 技术上他们真的非常类似—— 就是引用别人组件的实例对象 到自己的方法里边 然后调用别人的 完成自己的目的
我前边说过 关键不在于技术 而在于思想 这里我们就从这种让人迷惑的 很接近的技术实现方式出发 理解这几种种模式的相关性
适配器模式——转接头 接口之间的翻译
单向转接
其实单向转接头 实现起来我认为和代理一个道理的 只不过 代理追求的是 和被代理对象一个接口规范 而转接 就是用新接口取代旧接口就完事了嘛。。。
比方说 原来老的接口是2D4GHz 现在是2.4G+5G(5GHz)都能通用的 但是老的设备 比如我的老手机 它不支持这个新接口5Ghz 该怎么办?
public interface 2D4G {
// 以前没想过还会有别的频段的信号 默认是2.4GHz 所以这里直接emitSignal
public void emitSignal();
}
public class Mao implements 2D4G{
public void emitSignal() {
System.println.out("2D4G sig emited");
}
}
public class MyOldPhone {
public void UsingInternet(2D4G mao){
mao.emitSignal();
}
}
public class Me {
public static void main(String[] args) {
MyOldPhone myphone = new MyOldPhone();
myphone.UsingInternet(new Mao());
}
}
结果现在不提供旧的网络了 Mao也换成光猫了:
public interface 5G {
public void emit5Gsignal();
public void emitBothSignal();
public void emit2D4GSignal();
}
public class OpticalMao implements 5G {
public void emit5Gsignal() {
System.println.out("5G sig emited");
}
public void emit2D4Gsignal() {
System.println.out("2.4G sig emited");
}
public void emitBothsignal() {
System.println.out("Both 2.4G and 5G sig emited");
}
}
你会发现 我这光猫放进去他不行啊 他不是2D4G的规范 :
public class Me {
public static void main(String[] args) {
MyOldPhone myphone = new MyOldPhone();
myphone.UsingInternet(new OpticalMao());
}
}
这时 我们需要一个 光猫转普通猫 或者说应该是5G标准的实例 单向转到2.4G的实例
public class MaoAdapter implements 2D4G{
private 5G opticalMao = null;
public MaoAdapter(5G opticalMao)(
this.opticalMao = opticalMao;
}
public void emitSignal(){
this.opticalMao.emit2D4Gsignal();
}
}
然后 我 就能这么用我的手机了:
public class Me {
public static void main(String[] args) {
MyOldPhone myphone = new MyOldPhone();
myphone.UsingInternet(new MaoAdapter(new OpticalMao()));
}
}
其实就是一个外壳 说白了 一个为实例 做单向转接口规范的事情 或者说 就是个简单的翻译
双向转接
这个就稍微有点意思起来了 原来是 只是换了层皮 现在要做两面人 两边都要通
比方说我们举个例子 有个哥们 有支持5Ghz Wifi 接口的手机 但是悲惨的是 家里的Mao很老 只支持2.4G接口的信号 另外一个老哥 有光猫有5G 但是 只有个老手机 支持2.4G而已(没错 就是我哒)
这时我们需要一个双向接口!
我们来看看有了双向接口 理想的效果:
// 5G光猫 - 2.4G手机
public class 2D4GPhone {
public void UsingInternet(2D4G mao){
mao.emitSignal();
}
}
public class Me {
public static void main(String[] args) {
MyOldPhone myphone = new 2D4GPhone();
myphone.UsingInternet( new TwoWayAdapter(new OpticalMao()) );
}
}
// 2.4G猫 - 5G手机
public class 5GPhone {
public void UsingInternet(5G opticalMao){
opticalMao.emit2D4GSignal();
}
}
public class Me {
public static void main(String[] args) {
MyOldPhone myphone = new 5GPhone();
myphone.UsingInternet( new TwoWayAdapter(new Mao()) );
}
}
那么 这个双向接口应当如何设计? 其实还是翻译 只不过我们两种接口规范都需要支持才对!
public class TwoWayAdapter implements 5G, 2D4G{
private 5G opticalMao = null;
private 2D4G mao = null;
public TwoWayAdapter(5G opticalMao)(
this.opticalMao = opticalMao;
}
public TwoWayAdapter(2D4G mao)(
this.mao = mao;
}
// 2.4G手机会调用的
public void emitSignal(){
this.opticalMao.emit2D4Gsignal();
}
// 5G手机会调用的
public void emit2D4GSignal(){
this.mao.emitSignal();
}
// 真需要5G信号的部分 那没办法 只能搞个光猫了 或者骗骗自己:)至少能用吧
public void emit5Gsignal(){
this.mao.emitSignal();
}
public void emitBothSignal(){
this.mao.emitSignal();
}
}
可以发现 就是 有2.4G的实例 我调用它 完成既定接口需要的功能 然后套层壳当5G的实例使用:)
可以参考 鸭式辩型
像鸭子一样走路、游泳并且嘎嘎叫的鸟就是鸭子
因为鸭子这个接口规范的要求都满足 那就可以使用 客户不需要知道底层的细节
外观模式——套层皮
还记得之前的静态代理吗 我们就是引用别的组件 执行以下 执行的前后可能做些记录之类的 这是为了代理那个组件
同样的道理 如果代理一顿操作呢?比如需要好几个组件顺序执行 你同样可以引用 流程需要的所有组件 每个执行一遍即可 比如坐飞机=值机+安检+登记+降落+出站 说白了就是封装一层操作 没啥大不了的
这里可以举个简单的例子 比如你是老板 想做个网站 但是你也不懂技术 咋办?自然是使唤人来做啊 而且老板往往不会直接和下边员工布置具体的任务 ——他也不会啊 但是 他手下有主管经理 所以
老板所知的 只是经理能够安排好人手 搞定这个网站 而不是去管那些底层细节!
相当于 底层对老板而言不可见 也没必要见 老板只需要找到经理 这个经理就相当于封装了一层外观Facade
public class Boss(){
private Manager manager = null;
public Boss(Manager manager){
this.manager = manager;
}
private void IWantAWebsite(){
this.manager.executeWebsitePlan();
}
}
public class Manager(){
// ...
public void executeWebsitePlan(){
frontEndDeveloper().developing();
userEndDesigner().designing();
backEndDeveloper().developing();
OperationsEngineer().operating();
}
}
public class company(){
public static void main(String[] args){
Boss boss = new Boss(new Manager());
boss.IWantAWebsite();
}
}
可以发现 老板执行一句话 下边千军万马:)
迪米特原则 最少知识原则
看过专栏 有篇讲七大原则的兄弟可能还记得这个迪米特原则 说白了 老调重弹——客户不想 也没必要知道底层 你怎么代理 转换 外观 I dont care(idk) 反正你符合交货接口规范就行
迪米特原则强调 类与类直接 应当尽量减少耦合 换言之 只需要最小的知识即可 互相了解的越少越好 最好是没任何耦合:)
只和你的朋友说话 不要和陌生人讲
这样 耦合度 耦合的范围可以降到很低 出问题 定位容易 改错成本低
牵一发动全身的那种 往往就是 “知道的太多了” 依赖别的类 需要知道的东西太多了 耦合代码也太多了 GG
后记
还是那句话 重要的是思想 而不是技术实现
适配器重点是接口规范 乃至父类规范的适配(这个对于多继承语言有用 java只能说接口规范了)
外观的重点是屏蔽底层
代理的重点是 同规范 同功能 我给您代理
装饰器的重点是装饰 增添新特性