论坛首页 Java企业应用论坛

适配器模式【结构模式第六篇】

浏览 2114 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (4)
作者 正文
   发表时间:2009-10-23   最后修改:2010-10-20
适配器模式(Adapter Pattern)(另称-变压器模式):
把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作

1、(类适配器)模式所涉及的角色有:
1/目标(Target)角色:这就是所期待得到的接口。由于是类适配器模式,因此目标不可以是类。
2/源(Adaptee)角色:现有需要适配的接口。
3/适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,
   而必须是具体类。
//目标角色类
		public interface Target{
			//源类有的方法
			void sampleOperation1();
			//源类没有的方法
			void sampleOperation2();
		}
		源类(具体类)
		public class Adaptee{
			//源类含有的方法sampleOperation1()
			public void sampleOperation1(){}
		}
		//适配器角色
		public class Adapter extends Adaptee implements Target{
			public void sampleOperation2(){}
		}

2、(对象适配器)
1):模式所涉及的角色有:
1/目标(Target)角色:这就是所期待的接口,目标可以是具体的或抽象的类
2/源(Adaptee)角色:现有需要适配的接口
3/适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口,这一角色必须是具体类
//Target类
			public interface Target{
				//源类有的方法
				void sampleOperation1();
				//源来没有的方法
				void sampleOperation2();
			}
			源类(具体类)
			public class Adaptee{
				//源类含有的方法sampleOperation1()
				public void sampleOperation1(){}
			}
			//适配器类
			public class Adapter implements Target{
				private Adaptee adaptee;
				
				public Adapter(Adaptee adaptee){
					super();
					this.adaptee = adaptee;
				}
				//源类有的方法,适配器直接委派就可以了
				public void sampleOperation1(){
					adaptee.sampleOperation();
				}
				//源类没有,需要补充
				public void sampleOperation2(){
					//............
				}
			}

3、适配器模式的用意是将接口不同而功能相同或者相近的两个接口加以转换,这里面包括适配器角色补充了一个源角色没有的方法。

4、对象适配器模式的效果
1)一个适配器可以把多种不同的源适配到同一个目标,换言之,同一个适配器可以把源类和它的子类都适配到目标接口。
2)与类的适配器模式相比,要想置换源类的方法就不容易。如果一定要置换掉源类的一个或多个方法,就只好先做一个源
   类的子类,将源类的方法置换掉,然后再把原来的子类当做真正的源进行适配。
3)虽然要想置换源类的方法不容易,但是要想增加一些新的方法则方便的很,而且新增加的方法可同时适用于所有的源。

5、在什么情况下使用适配器模式
1)系统需要使用现有的类,而此类的接口不符合系统的需要。
2)想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
   这些源类不一定有很复杂的接口。
3)(对对象适配器模式而言)在设计里,需要改变多个已有的子类的接口,如果使用类的适配器模式,就要针对每一个子类做
   一个适配器,而这不太实际
//Itermeration类
		 import java.util.Iterator;
		 import java.util.*;
		 import java.util.Enumeration;
		 
		 public class Itermeration implements Enumeration{
		 	private Iterator it;
		 	
		 	public Itermeration(Iterator it){
		 		this.it = it;
		 		
		 		//是否存在下一个元素
		 		public boolean hasMoreElements(){
		 			return it.hasNext();
		 		}
		 		
		 		//返还下一个元素
		 		public Object nextElement() throws NoSuchElementException{
		 			return it.next();
		 		}
		 	}
		 }
		 
		 //Enuterator类
		 import java.util.Iterator;
		 import java.util.*;
		 import java.util.Enumeration;
		 
		 public class Enuterator implements Iterator{
		 	Enumeration enum;
		 	
		 	public Enuterator(Enumeration enum){
		 		this.enum = enum;
		 	}
		 	
		 	//是否存在下一个元素
		 	public boolean hasNext(){
		 		return enum.hasMoreElements();
		 	}
		 	
		 	//返还下一个元素
		 	public Object next() throws NoSuchElementsException{
		 		return enum.nextElement();
		 	}
		 	
		 	//删除当前的元素(不支持)
		 	public void remove(){
		 		throw new UnsupportedOperationException();
		 	}
		 }
		 --------------------------------------------------
		
		//立方体类
		public class Cube{
			private double width;
			
			public Cube(double width){
				this.width = width;
			}
			
			//计算体积
			public double calculateVolume(){
				return width*width*width;
			}
			
			//计算面积
			public double calculateFaceArea(){
				return width*width;
			}
			
			//长度的取值方法
			public double getWidth(){
				return this.width;
			}
			
			//长度的赋值方法
			public void setWidth(double width){
				this.width = width;
			}
		}
		
		//目标接口角色
		public interface BallIF{
			//计算面积
			double calculateVolume();
			//半径的取值方法
			double getRadius();
			//半径的赋值方法
			void setRadius(double radius);
		}
		
		//适配器类角色
		public class MagicFinger implements BallIF{
			private double redius = 0;
			private static final double PI = 3.14D;
			private Cube adaptee;
			
			public MagicFinger(Cube adaptee){
				super();
				this.adaptee = adaptee;
				radius = adpatee.getWidth();
			}
			
			//计算面积
			public double calculateArea(){
				return PI*4.0D*(radius);
			}
			
			public double calculateVolume(){
				return PI*(4.0D/3.0D)*(radius*radius*radius);
			}
			
			//半径取值方法
			public double getRadius(){
				return radius;
			}
			
			public void setRadius(double radius){
				this.radius = radius;
			}
		}
		


6、本模式在实现的时候有以下这些值得注意的地方;
1) 目标接口可以省略。此时,目标接口和源接口实际上是相同的。由于源是一个接口,而适配器类是一个类(或抽象类)
   因此这种做法看似平庸而并并平庸,它可以使客户端不必实现不需要的方法。
2)适配器类可以是抽象类,这可以在缺省适配情况下看到。
3)带参数的适配器模式。使用这种方法可以根据参数返还一个合适的实例给客户端

7、适配器模式与其他模式的关系
1)适配器模式与桥梁模式的关系
桥梁模式的用意是要把实现和它的接口分开,以便它们可以独立地变化。桥梁模式并不是用来把一个已有的对象接到不相
匹配的接口上的。当一个客户端只知道一个特定的接口,但是有必须与具有不同接口的类打交道时,就应当使用适配器模式。
2)适配器模式与装饰模式的关系
一个装饰类也是位于客户端和另外一个Compontent对象之间的,
在它接到客户端的调用后把调用传给一个或几个Component对象。
一个纯粹的装饰类必须与Compotent对象在接口上的完全相同,并增强后者的功能。
与适配器类不同的是,装饰类不能改变它所装饰的Compotent对象的接口。
3)适配器模式与缺省适配模式的关系
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics