首页 > 代码库 > 设计模式(7)--适配式模式与外观模式
设计模式(7)--适配式模式与外观模式
转换接口。
引入新原则: ” 最少知识“原则 作用为 外观模式
面向对象的适配器:将一个接口转换成另一个接口,以符合客户的期望。
对象适配器 与 类适配器
OO原则:(1)封装变化 (2)多用组合,少用继承 (3)针对接口编程,不针对实现编程 (4)为交互对象之间的松耦合设计而努力 (5)类应该对扩展开放,对修改关闭。(6) 依赖抽象,不要依赖具体类。(7)只和朋友交流。
OO模式:
适配器模式-:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。 (让客户从实现的接口解耦)
外观模式 :提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
例1: 客户需要一只鸭子,但因为没有鸭子了, 所以只好拿火鸡去冒充鸭子。
//鸭子接口 public interface Duck{ public void quack(); public void fly(); }
//绿头鸭是鸭子的子类 public class MallardDuck implements Duck{ public void quack(){ syso("Quack"); } public void fly(){ syso("i‘m flying"); } }
//火鸡接口
public interface Turkey{
public void gobble();
public void fly();
}
//因为现在需要火鸡去冒充鸭子,所以需要一个火鸡适配器 (此适配器需要实现目标接口(鸭子),被持有被适配者的引用(火鸡)) public class TurkeyAdapter implements Duck{ Turkey turkey; public TurkeyAdapter(Turkey turkey){ this.turkey = turkey; } public void quack(){ turkey.gobble(); } public void fly(){ for(int i=0;i<5;i++){ turkey.fly(); //因为火鸡飞的短所以需要飞5次 } } }
//测试适配器 public class DuckTestDrive{ public static void main (String[] args){
MallardDuck duck = new MallardDuck(); //先创建一只鸭子
WildTurkey turkey = new WildTurkey(); //和一只火鸡
Duck turkeyAdapter = new TurkeyAdapter(turkey); //将火鸡包装到火鸡适配器中,使它看起来像一只鸭子
testDuck(turkeyAdapter);
}
static void testDuck(Duck duck){
duck.quack(); //调用的是火鸡适配器的咕咕叫
duck.fly(); //适配器飞行了五次
// testDuck()方法根本不知道,这其实是一只假装鸭五的火鸡。
}
}客户使用适配器的过程如下:
(1)。客户通过目标接口调用适配器的方法对适配器发出请求 // 鸭子接口调用 火鸡适配器
(2)。适配器使用被适用者接口把请求转换成被适配者的一个或多个调用接口。
(3)。客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用。
一个适配器需要做多少“适配”工作? 如果需要实现的一个很大的目标接口,似乎有“很多"工作要做。
的确如此。实现一个适配器所需要进行的工作,和目标接口的大小成正比。
一个适配器只能够封装一个类吗?
适配器模式的工作是将一个接口转换成另一个。一般情况都是让一个适配器包装一个被适配者。 转换接口。
如果需要让一个适配器包装多个被适配者。这涉及到另一个模式,外观模式(Facade Pattern) 简化接口。
一个系统中新旧代码共存,旧的部分期望旧的厂商接口,但新的厂商接口忆经编写了一部分了。
双向适配器。 需要实现所涉及的两个接口。
适配器分为 对象适配器 和 对象适配器
对象适配器类图
这个适配器模式充满着良好的OO设计原则:使用对象组合,以修改的接口包装被适配者,这种做法还有额外的优点,那就是,被适配者的任何的子类,都可以搭配着适配器使用。
类适配器 (类图) 类适配器需要 多继承 因为 Java中没有类适配器
唯一的差别就在于 适配器继承了Target和Adaptee 。 而对象适配器利用组全方式将请求传送给被适配者。
优点: 不需要重新实现整个被适配者。必要的时候 也可以覆盖被适配者的行为。因为,是利用继承的方式。
例2: 旧的枚举器 与 新的迭代器
早期的集合(collection)类型如: Vector 、Stack 、Hashtable 都实现了一个名为elemetns()的方法。 该方法返回一个Enumeration(举)
这个Enumeration接口可以逐一走过此集合内的每个元素,而无需知道它们在集合内是如何管理的。
当Sun 推出更新的集合类时,开始使用了Iterator(迭代器)接口, 不同的是,迭代器提供了删除功能。
//枚举接口 public interface Enumeration{ public boolean hasMOreElements(); //是否在集合中还有更多无素 pbulic Object nextElement(); //取得集合中的下一个元素 }
//迭代器接口 public interface Iterator{ public boolean hasNext(); //用来取代枚举接口中的hasMoreElements(). 这个方法告知你是否已经遍历中的所有项。 public Object next(); // 取得集合中的下一个元素 public void remove() // 从集合中删除一个项 }现在经常面对遗留代码,这些代码暴露出来的枚举器接口,但又希望在新的代码中使用迭代器。 因此我们需要一个适配器。
目标接口 Iterator 被适配者接口 Enumeration
因为 iterator 中 多一个remove() 方法//适配中remove() public void remove(){ thorw new UnsupportedOperationException(); }
外观模式:
把一系列接口封装起来为一个接口(持系列接口为引用 组合方式)。 需要系列接口作为参数
外观模式: 提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
” 最少知识 “ 原则 : 只和你的密友谈话。
减少对象之间的交互,只留下几个密友。
就任何对象而言,在该对象的方法内,我们只应该调用 属于以下范围的方法:
(1). 该对象本身
(2). 被当做方法的参数而传递进来的对象
(3). 此方法所创建或实例化的对象
(4). 对象的任何组件。
//不采用原则
public float getTemp(){ Thermometer thermometer = station.getTermometer(); return thermometer.getTemperature(); }
//采用原则
public float getTemp(){ return station.getTemperature(); //应用此原则时,我们在加进一个方法用来向温度计请求温度 }
此原则还有一个名称 叫 做 迪米特法则(Law of Demeter)
迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。英文简写为: LoD.
优点: 减少对象之间的依赖 , 减少软件维护成本。
缺 点: 会导致更多”包装“类被制造出来,以处理和其他组件的沟通,这可能会导致复杂度和开发时间的增加。并降低运行时的性能。
Java中 还有哪些违反最少知识原则 ?
System.out.println();
要点:
(1)要需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器。
(2)当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。
(3)适配器改变接口以符合客户的期望。
(4)外观将客户从一个复杂的子系统中解耦。
(5)实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂度而定。
(6)实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行。