`

Adapter - 适配器模式

    博客分类:
  • Java
OOP 
阅读更多

假设模型:媒体播放器,既能播放音频文件AudioMedia,又能播放视频文件VideoMedia 。其中音频文件又分MP3格式和WMV格式;视频文件又分MPEG格式和RM格式。

经过功能分析,不管哪种类型的文件都要有一个播放的方法,也就是Play() ,原型结构如图:

Adapter_Initial

当各个类之间继承/实现关系理清楚后,我们现在可以实现一个播放器类MediaPlayer,它可以播放任何一种格式(MP3WAVRMMPEG)的文件。

在此我们要注意一点:在调用类对象的属性和方法时,尽量避免将具体类对象作为传递参数,而应传递其抽象对象,更好地是传递接口,将实际的调用和具体对象完全剥离开,这样可以提高代码的灵活性。(使用接口有什么好处?那就是你的主程序可以在没有具体业务类的时候,同样可以编译通过。因此,即使你增加了新的业务,你的主程序是不用改动的。)

 

在本文中体现在MediaPlayer代码中,如下所示:

package adapter_media;

public class MediaPlayer {

         public void Play(IMedia media){

                   media.Play();

         }

}

相关代码如下:

package adapter_media;

public interface IMedia {
	public void Play();
}

 

package adapter_media;

public abstract class AudioMedia implements IMedia{
	public abstract void Play();
}

 

package adapter_media;

public abstract class VideoMedia implements IMedia {
	public abstract void Play();
}

 

package adapter_media;

public class MP3 extends AudioMedia {

	@Override
	public void Play() {
		System.out.println("Play AudioMedia with the type of MP3");
	}
}

 

package adapter_media;

public class WAV extends AudioMedia {

	@Override
	public void Play() {
		System.out.println("Play AudioMedia with the type of WAV");
	}
}

 

package adapter_media;

public class MPEG extends VideoMedia {

	@Override
	public void Play() {
		System.out.println("Play VideoMedia with the type of MPEG");
	}
}

 

package adapter_media;

public class RM extends VideoMedia {

	@Override
	public void Play() {
		System.out.println("Play VideoMedia with the type of RM");
	}
}

 

 

package adapter_media;
/**
 *************************************
  * @Title   MediaPlayer.java
  * @Author  张作强
  * @Date    2010-8-15
  * @Comment 在调用类对象的属性和方法时,尽量避免将具体类对象作为传递参数,
  * 		   而应传递其抽象对象,更好地是传递接口,
  *          将实际的调用和具体对象完全剥离开,这样可以提高代码的灵活性。
 *************************************
 */
public class MediaPlayer {
	public void Play(IMedia media){
		media.Play();
	}
}

 

引入Adapter模式:

原来的RMMPEG类继承了VideoMedia抽象类,而VideoMedia类又实现了IMedia接口,该接口仅仅提供了Play()方法。现在我们希望为RMMPEG提供与AudioMedia不同的属性和方法。例如,对于视频媒体而言,应该有一个调整画面大小的方法,如Resize()。而这个方法是IMedia接口所不具备的。

 

那么怎样为RMMPEG类提供IMedia接口所不具备的Resize()方法呢?非常自然地,通过这个问题我们就引出Adapter模式的命题了。首先,要假设一个情况,就是原文的所有代码,我们是无法改变的,这包括暴露的接口,类与接口的关系等等,都无法通过编码的方式实现新的目标。只有这样,引入Adapter模式才有意义。

 

Adapter模式分为两种:类的Adapter模式、对象的Adapter模式。

 

下面试图根据本例对两种方式进行说明及实现。在实现Adapter模式之前,有必要看看原来的类结构:

  

一、类的Adapter模式

既然要让RMMPEG具有Resize()方法,最好的办法就是让它们直接实现IVideoScreen接口。然而受到条件的限制,这两个类的类型是不可修改的。唯一可行的办法就是为相应的类新引入一个类类型,这就是Adapter模式中所谓的Adapter类了。它好比是一个转接头,通过它去实现IVideoScreen接口,同时又令其继承原有的RMMPEG类,以保留原有的行为。类图如下:

 

Adapter_Class_Model

 

图中的类RMAdapterMPEGAdapter就是通过Adapter模式获得的对象,它在保留了原有行为的同时,又拥有了IVideoScreen的功能。

相关代码如下:

package adapter_media;

public interface IVideoScreen {
	public void Resize();
}

 

package adapter_media;

public class MPEGAdapter extends MPEG implements IVideoScreen {

	public void Resize() {
		System.out.println("Play VideoMedia with the size of MPEG");
	}
	
	@Override
	public void Play() {
		super.Play();
	}
}

 

package adapter_media;

public class RMAdapter extends RM implements IVideoScreen {

	public void Resize() {
		System.out.println("Play VideoMedia with the size of RM");
	}
	
	@Override
	public void Play() {
		super.Play();
	}
}

 

也许很多人已经注意到了,在使用这种方式建立Adapter时,存在一个局限,就是我们必须为每一个要包裹(Wrapping)的类,建立一个相应的Adapter类。如上所述的RM对应RMAdapterMPEG对应MPEGAdapter。必须如此,为什么呢?虽然RMMPEG继承了同一个抽象类VideoMedia,但其Play()方法,可能是不相同的。此时,相对应的Adpater类只有直接继承该具体类,方才可以保留其原来的Play()方法的行为本质。

 

分享到:
评论
1 楼 csdn_zuoqiang 2010-08-15  
OOP中很重要的思想是,尽量使用聚合而非继承。让我们换一种思路来考察Adapter模式。

二、对象的Adapter模式

对象的Adapter模式,与类的Adapter模式,最大的区别就是不采用继承的方式,而是将要包裹的对象,以聚合的方式放到Adapter中,然后用委托的方式调用其对象的方法,实现类图如下:


以这种方式形成的VideoAdapter,由于没有和RM、MPEG直接发生关系,并通过在构造函数传递参数的方式,等待客户端使用Adapter时,才将具体的VideoMedia对象传递给Adapter,显得耦合度更加松散,更加灵活。

对于对象的Adapter模式(在VideoMedia)中,按照传递对象的方式又可以分为:通过构造函数传递被包裹对象的方式、通过方法属性方式传递被包裹对象。

相关代码如下:
package adapter_media;

public class VideoAdapter implements IVideoScreen {

	private VideoMedia _video;
	
	//无参构造函数
	public VideoAdapter() {
	}
	
	//构造函数方式传递对象
	public VideoAdapter(VideoMedia videoMedia) {
		this._video = videoMedia;
	}
	//方法属性方式传递对象,同时要求此类必须有一个无参构造函数
	public void setVideoMedia(VideoMedia video) {
		this._video = video;
	}

	public void Play() {
		_video.Play();
	}

	public void Resize() {
		System.out.println("Play VideoMedia with the size of " + _video.getClass().getSimpleName());
	}

}


测试类:

package adapter_media;
/**
 *************************************
  * @Title   TestMedia.java
  * @Author  张作强
  * @Date    2010-8-15
  * @Comment 原有类型和经过Adapter扩展后的类型
 *************************************
 */
public class TestMedia {
	public static void main(String[] args) {
		IMedia mp3 = new MP3();
		IMedia wav = new WAV();
		IMedia rm = new RM();
		IMedia mpeg = new MPEG();
		
		MediaPlayer media = new MediaPlayer();
		System.out.println("================ type =================");
		media.Play(mp3);
		media.Play(wav);
		media.Play(rm);
		media.Play(mpeg);
		
		System.out.println("============= 类的Adapter模式 =============");
		IVideoScreen rmAdapter = new RMAdapter();
		rmAdapter.Resize();
		((RMAdapter) rmAdapter).Play();
		
		IVideoScreen mpegAdapter = new MPEGAdapter();
		mpegAdapter.Resize();
		((MPEGAdapter) mpegAdapter).Play();
		
		System.out.println("=============== 对象的Adapter模式(构造函数方式传递对象) ===============");
		VideoAdapter rmAdapter2 = new VideoAdapter(new RM());
		rmAdapter2.Play();
		rmAdapter2.Resize();
		
		VideoAdapter mpegAdapter2 = new VideoAdapter(new MPEG());
		mpegAdapter2.Play();
		mpegAdapter2.Resize();
		
		System.out.println("=============== 对象的Adapter模式(方法属性方式传递对象) ===============");
		VideoAdapter rmAdapter3 = new VideoAdapter();
		rmAdapter3.setVideoMedia(new RM());
		rmAdapter3.Play();
		rmAdapter3.Resize();
		
		VideoAdapter mpegAdapter3 = new VideoAdapter();
		mpegAdapter3.setVideoMedia(new MPEG());
		mpegAdapter3.Play();
		mpegAdapter3.Resize();
	}
}


结果:

================ type =================
Play AudioMedia with the type of MP3
Play AudioMedia with the type of WAV
Play VideoMedia with the type of RM
Play VideoMedia with the type of MPEG
============= 类的Adapter模式 =============
Play VideoMedia with the size of RM
Play VideoMedia with the type of RM
Play VideoMedia with the size of MPEG
Play VideoMedia with the type of MPEG
=============== 对象的Adapter模式(构造函数方式传递对象) ===============
Play VideoMedia with the type of RM
Play VideoMedia with the size of RM
Play VideoMedia with the type of MPEG
Play VideoMedia with the size of MPEG
=============== 对象的Adapter模式(方法属性方式传递对象) ===============
Play VideoMedia with the type of RM
Play VideoMedia with the size of RM
Play VideoMedia with the type of MPEG
Play VideoMedia with the size of MPEG


比较两种实现方式的类图,可以得出两个结论:

1、 对象的Adapter模式,减少了对象的个数;
2、 耦合度更加松散;

通过运用Adapter模式,扩展了新的接口,而原有的类型并不需要做任何改变,这就是Adapter模式的实质,也是为什么取名为Adapter的原因之所在了。同时,我们要注意的是,在运用Adapter模式时,必须审时度势,根据具体的情况,抉择最优的方式,或者采用类的Adapter模式,或者采用对象的Adapter模式。决定权在与你,菜单给你送上来了,看看自己的腰包,想想点什么样的菜吧。

参考地址:http://www.cnblogs.com/wayfarer/articles/70453.html

相关推荐

    设计模式--适配器模式java例子

    在“设计模式--适配器模式java例子”中,我们可以假设有一个遗留的`OldLibrary`,它的接口与我们当前项目的需求不一致。例如,`OldLibrary`有一个`OldDevice`类,它有一个方法`oldMethod()`,而我们的新系统需要一个...

    CCNU的设计模式-适配器模式

    适配器模式有两种实现方式,一种是类适配器模式,一种是对象适配器模式。类适配器模式通过多重继承的方式来实现适配器,而对象适配器模式则通过组合的方式实现。 类适配器模式中,适配器类继承自Adaptee类,并实现...

    设计模式之--适配器模式

    适配器模式是一种常用的设计模式,它在软件工程中扮演着重要的角色,特别是在解决系统间的兼容性和接口不匹配问题时。适配器模式的核心思想是将一个类的接口转换成客户希望的另一个接口,使原本由于接口不兼容而无法...

    23种设计模式--适配器模式

    适配器模式是一种软件设计模式,它允许两个不兼容的接口之间进行通信。在软件工程中,这种模式常被用来解决旧系统与新系统、第三方库或者不同组件之间的接口不匹配问题。适配器模式的核心思想是通过创建一个新的类...

    设计模式 - 适配器模式(C++实例)

    在`DesignMode_Adapter`这个压缩包文件中,可能包含了相关的C++源码示例,演示了如何创建和使用适配器模式。这些源码可能包括了目标接口、原始接口、适配器类的定义以及客户端如何通过适配器进行调用的示例。通过...

    设计模式-适配器模式(讲解及其实现代码)

    适配器模式是一种常用的设计模式,它在软件工程中扮演着重要的角色,特别是在处理系统集成、遗留代码重用以及不同接口之间兼容性问题时。适配器模式的主要目的是将两个不兼容的接口融合在一起,使得原本无法直接协作...

    java常用设计模式-适配器模式

    java常用设计模式-适配器模式 适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间进行通信。这种模式可以在不修改现有代码的情况下重用现有类,并且可以使不兼容的接口之间进行通信。 ...

    c++设计模式-结构型模式-适配器模式

    c++设计模式-结构型模式-适配器模式,其他工程,c++源码。适配器模式(Adapter)的定义如下:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

    设计模式--适配器模式

    适配器模式是一种常用的设计模式,它在软件工程中扮演着重要的角色,特别是在解决系统间的兼容性和接口不匹配问题时。适配器模式的核心思想是将一个类的接口转换成客户希望的另一个接口,使原本由于接口不兼容而无法...

    PHP5设计模式-适配器模式实现

    适配器模式是一种结构型设计模式,它的主要目的是使不兼容的接口能够协同工作。在实际开发中,我们可能会遇到这样的情况:一个类库或者服务提供了一个接口,而我们的代码需要使用另一个接口。适配器模式就充当了两者...

    设计模式实验报告-适配器模式.docx

    适配器模式(Adapter Pattern)是一种结构型设计模式,其主要目的是将一个类的接口变换成客户端所期待的另一种接口。通过这种方式,原本由于接口不兼容而无法一起工作的类可以顺利合作。适配器模式有两种实现方式:...

    OC-适配器模式-适配支付接口

    适配器模式是一种软件设计模式,它允许两个不兼容的接口之间进行通信。在本文中,我们将深入探讨适配器模式的应用,特别是在OC(Objective-C)中如何利用它来适配支付接口。适配器模式的核心思想是创建一个新的类,...

    8.设计模式-适配器模式1

    在对象适配器模式中,适配器类(Adapter)实现目标接口(Target),并将适配者类(Adaptee)的对象作为内部成员变量持有。当调用适配器类的方法时,适配器会转发调用给适配者对象,经过适当的转换处理,返回客户需要...

    讲故事,学(Java)设计模式-适配器模式Java开发Ja

    类适配器模式通常涉及到接口的继承,例如,假设有一个旧的`OldDevice`接口,它与新的`NewDevice`接口不兼容,我们可以通过创建一个适配器类`Adapter`,继承`OldDevice`并实现`NewDevice`,这样`Adapter`就可以作为`...

    Adapter(适配器模式)

    适配器模式是一种软件设计模式,它允许两个不兼容的接口之间进行通信。在软件工程中,当系统中存在已有的类或库,而我们希望使用它们的功能,但其接口与我们的需求不匹配时,适配器模式就显得尤为重要。通过适配器,...

    设计模式结构型-适配器

    **适配器模式**(Adapter Pattern)属于结构型设计模式,它的目的是将一个接口转换成客户希望的另一个接口,从而使得原本由于接口不兼容而无法一起工作的那些类能够合作。适配器模式有两种形式:类适配器模式和对象...

    设计模式 - 适配器

    适配器模式(Adapter Pattern)是一种结构型设计模式,它允许两个不兼容的接口之间进行通信。在实际应用中,我们常常遇到这样的情况:一个系统需要使用现有的类,但其接口与系统的需求不匹配。适配器模式能解决这种...

    codelab-adapter-4_9_1-win.zip

    在计算机编程中,适配器(Adapter)是一种设计模式,它的作用是使两个不兼容的接口能够协同工作。在这个特定的案例中,codelab-adapter可能是为了使Scratch3与特定的教学平台或设备(如Codelab)进行无缝对接,提供...

    设计模式专题之(八)适配器模式---设计模式适配器模式示例代码(python--c++)

    在压缩包中,`Adapter.cpp`可能是C++实现适配器模式的代码文件,它可能包含了`CPlusPlusClass`和`CppAdapter`的定义。而`Adapter.py`则是Python版本的适配器实现,可能会包含`PythonAdapter`类,它将`CPlusPlusClass...

    Android开发---适配器

    在Android开发过程中,适配器(Adapter)是一种非常重要的设计模式,它主要应用于数据与UI之间的桥梁搭建,使得视图能够灵活地展示来自不同数据源的数据。简单来说,适配器就像是一个中介者,将复杂的数据结构转换成...

Global site tag (gtag.js) - Google Analytics