适配器模式(Adapter)

适配器的核心思想:

把原有的接口转变成调用者期待的接口,从而使不同接口的类可以一起工作。


适配器中包含三个角色:

源角色Adaptee:需要适配的目标类或者接口;

目标角色Target:所期望得到的接口;

适配器角色Adapter:适配器类是本模式的核心,用来把源接口转换成目标接口,显然这一角色不可以是接口,而必须是具体类。


适配器也叫做包装器模式,根据适配的对象不同可以分为三种:

类的适配器模式:用于对类进行适配;

对象的适配器模式:用于对对象进行包装;

接口适配器模式:用于对接口抽象化。

类的适配器模式

源类:

Source类是具体的原始的类,是待适配的对象,它拥有一个函数operation1();

package model;
class Source {
public void operation1(){
System.out.println("原始类的方法");
}
}


目标类:

Targetable是要适配的目标接口,它拥有一个与Source同样的接口函数operation1(),并提供了一个新的接口函数operation2(),该函数是要扩展的功能。

public interface Targetable {
public void operation1();
public void operation2();
}


适配器类:

它必须继承Source类,并实现Targetable接口,从而将Source的功能扩展到Targetable接口所具有的功能。

public class Adapter extends Source implements Targetable{
@Override
public void operation2() {
// TODO Auto-generated method stub
System.out.println("适配目标后的方法");
}
}


测试类:

public class AdapterTest {
public static void main(String[] args) {
Targetable obj=new Adapter();
obj.operation1();
obj.operation2();
}
}


结果:

原始类的方法
适配目标后的方法

对象的适配器模式

用来对目标对象进行包装,因此又叫做包装器模式。


包装器类:

Wrapper是包装其类,它与Adapter适配器不同,它不需要继承Source,但必须拥有一个Source类型的对象source,该对象在构造函数中被赋值,在该包装器的operation1()函数中,需要调用source的operation1(),这样就实现了对原有对象的调用;同时扩展实现了Targetable的operation2()函数。

public class Wrapper implements Targetable{
private Source source;
public Wrapper(Source source) {
super();
this.source = source;
}
@Override
public void operation1() {
// TODO Auto-generated method stub
source.operation1();
}
@Override
public void operation2() {
// TODO Auto-generated method stub
System.out.println("包装目标类后的方法");
}
}


实现方法:

public class WrapperTest {
public static void main(String[] args) {
Source source=new Source();
Targetable obj=new Wrapper(source);
obj.operation1();
obj.operation2();
}
}


结果:

原始类的方法
包装目标类后的方法


在另外一本书上以及其他博客上的内容似乎略有不同:

装饰设计模式就是通过包装一个类,动态的为它增加功能的一种设计模式。

package model;
class Car{
private String carName;
public Car(String carName) {
super();
this.carName = carName;
}
public void show(){
System.out.println("我是"+carName+",具有基本功能");
}
}
class RadarCar{
private Car myCar;
public RadarCar(Car myCar) {
super();
this.myCar = myCar;
}
public void show(){
myCar.show();
System.out.println("具有倒车雷达功能");
}
}
public class CarTest {
public static void main(String[] args) {
Car benz=new Car("benz");
System.out.println("-----------装饰前----------------");
benz.show();
RadarCar decaratedCar_benz=new RadarCar(benz);
System.out.println("-----------装饰后----------------");
decaratedCar_benz.show();
}
}

结果:

-----------装饰前----------------
我是benz,具有基本功能
-----------装饰后----------------
我是benz,具有基本功能
具有倒车雷达功能


该实现并没有用到适配器和其他的接口,而是直接在一个类中对另一个类的对象进行扩展,而观察网上其他的博主的博客内容也显示,不需要改变装饰对象的接口。

(http://blog.csdn.net/zhengpeitao/article/details/17303233)

装饰模式(Decorator)也叫包装器模式(Wrapper)。GOF在《设计模式》一书中给出的定义为:动态地给一个对象添加一些额外的职责

(http://www.cnblogs.com/xrq730/p/4908940.html)

装饰器模式和适配器模式的区别

其实适配器模式也是一种包装(Wrapper)模式,它们看似都是起到包装一个类或对象的作用,但是它们使用的目的非常不一样:

1、适配器模式的意义是要将一个接口转变成另外一个接口,它的目的是通过改变接口来达到重复使用的目的

2、装饰器模式不要改变被装饰对象的接口,而是恰恰要保持原有的借口哦,但是增强原有接口的功能,或者改变元有对象的处理方法而提升性能

所以这两种设计模式的目的是不同的。

(http://blog.sina.com.cn/s/blog_4d14c288010124bo.html)

装饰模式适配器模式都有一个别名叫包装模式,但包装的形式是不一样的。

定义上:

装饰模式:对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。使用原来被装饰的类的一个子类的实例,把客户端的调用委派到被装饰类。

适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。

从定义上看装饰模式是对核心对象或者功能的扩展,适配器模式是把对象或者功能放到一个新对象中引用。举个例子,现在书城卖道德经的书,有线装版,有精装版,有日文版,有英文版,其中线装版和精装版就是装饰模式,日文版和英文版就是适配器模式,各种版本都是为迎合不同消费者的不同需求。为什么呢?因为线装版和精装版的道德经虽然包装不同,但内容相同,日文版和英文版就不同,这两个版本的内容就可能和原版的不同,文化差异嘛,翻译的内容虽来自道德经,但根据不同国家的文化,思维逻辑什么的就可能改变一些想法。

使用条件:

装饰模式一般在下列情况使用:需要扩展一个类的功能或者给你个类增加附加责任;需要动态的给一个对象增加功能,这些功能可以再动态的撤销;需要增加有一些基本功能的排列组合而产生非常大量的功能,从而使得继承关系变得不现实。

适配器模式一般使用的情况包括:系统需要使用现有的类,但此类已经不符合系统的需要;

想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的的类一起工作。适配器模式在系统升级的时候使用的频率很高,对旧系统的一些功能方法在新系统中引用。

装饰模式java中的I/O文件的操作中都有体现。

Java的IO库中处理流的类有FIleInputStream,FileOutputStream,DataInputStream,DataOutputStream类等。在InputStream,OutputStream,Reader,Writer结构的内部,有一些流处理器可以对另一些流处理器起到装饰作用,形成新的,改善的流处理器。这就体现了装饰模式的作用。同时在一些流处理器的内部有对其他流处理器的功能的适配引用,这体现了适配器模式的优点。

接口的适配器模式

为原有的接口实现一个默认的抽象,在该抽象中编写每一个接口的默认值,当我们需要编写一个具类时,只需要继承该抽象类,而不需要实现原有的接口。


源接口:

public interface Sourcable {
public void operation1();
public void operation2();
}


默认适配器类:

public abstract class DefaultWrapper implements Sourcable {
public void operation1(){}
public void operation2(){}
}


源接口的实现子类:

public class SouceSub1 extends DefaultWrapper{
public void operation1(){
System.out.println("源接口的一个实现子类Sub1");
}
}


源接口的实现子类:

public class SouceSub2 extends DefaultWrapper{
public void operation2(){
System.out.println("源接口的一个实现子类Sub2");
}
}


测试类:

public class DefaultWrapperTest {
public static void main(String[] args) {
Sourcable source1=new SouceSub1();
Sourcable source2=new SouceSub2();
source1.operation1();
source1.operation2();
source2.operation1();
source2.operation2();
}
}


结果:

源接口的一个实现子类Sub1
源接口的一个实现子类Sub2

何时使用适配器模式

类的适配器模式:当希望一个类转换成另一个另一个接口时,可以模仿Adapter的做法来构造一个新的适配器,该类继承原有的类并实现新的接口即可。

对象的适配器模式:当希望一个对象转换成另一个接口时,可以模仿Wrapper的做法来构造一个新的包装类,该类调用原有的类并实现新的接口即可。

默认适配器模式:当不希望实现所有的方法时,可以模仿DefaultWrapper的做法构造一个抽象类,给出所有方法的默认实现,这样,从这个抽象类继承下去的子类就不必实现所有的方法了。


小结:

本来以为设计模式都是看不懂的,尝试学了之后才发现很多在平时的学习书本上的代码时就已经接触过了,不足的是,看着书本的时候感觉好像懂了,但是在这里进行归纳的时候依旧照着书本来,似乎真正感悟的很少。





























  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值