Adapter - 适配器模式

假设模型:媒体播放器,既能播放音频文件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()方法的行为本质。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值