设计模式之适配器模式

        如果我们有一个方块,有一个圆孔,并且方块的外接圆半径大于圆孔的半径,现要求在不改变这两者自身尺寸的情况下,将这两者作为一个整体。按理说,因为方块的外接圆半径大于圆孔,硬塞是塞不进去了。那么我们可以换种思路,就是设计一个物体,既要能够和圆孔合为一个整体,又能够和方块合成一个整体,就像我们手机常用的转接口一样,这样三者合为一体,那么方块和圆孔间接的合为一体了,而且就算两者发生改变了,也互不干扰,只需要修改转接口即可。这种情况也就是我们今天要讲的适配器模式会遇到的场景。通过上述例子,我们也明白了适配器模式的作用,就是相当于生活中常用的转接口的作用。适配器模式将一个类的接口,转换成客户期望的另一个接口;适配器让原本接口不兼容的类可以合作无间。

1.适用性与优缺点
1.适用性
a.你想使用一个已经存在的类,而它的接口不符合你的要求
b.你想创建一个可以复用的类,该类可以与其它不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
c.你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它们的父类接口。

2.优点
a.更好的复用性
b.更好的扩展性

3.缺点
过多的使用适配器会让系统紊乱,看到调用的是A接口,其实内部适配成了B接口的实现,透明性较低。

2.示例讲解
        适配器模式分为对象适配器和类适配器,前者使用接口形式,适配器通过组合的形式将请求传送给被适配者;而后者适配器继承了目标类以及被适配者。一般情况下,我们会使用对象适配器,更符合我们的设计原则,也体现了多态的特点。接下来我们讲的示例就是对象适配器。其实就是对象适配器的原理大致是:适配器实现目标接口,并将被适配者对象传入适配器,并且通过目标类的方法封装被适配者的方法(即在目标类方法中调用被适配者的方法),这样外部体现的是目标对象的特征,而看不到被适配者的具体方法。
        我想大家都听过指鹿为马的故事吧,那么我们今天就来举一个类似的实例,就是将火鸡接口变为鸭子接口。那么我们就只需要让适配器实现鸭子接口,然后将火鸡对象传入适配器中,然后在实现鸭子接口的方法中调用火鸡相应的方法,这样这个适配器就成了鸭子对象。
首先定义一个Duck接口,该接口有表示鸭子Duck特性的两个方法,quack()和fly(),并且实现一个Duck类:
package adapterpattern;

public interface Duck {
	public void quack();
	public void fly();

}
package adapterpattern;

public class MallardDuck implements Duck {

	@Override
	public void quack() {
		// TODO Auto-generated method stub
		System.out.println("Quack");

	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println("I'm flying");
	}

}


然后定义一个火鸡接口,该接口也有两个代表火鸡特性的方法,gobble()和fly(),并且实现一个火鸡类:

package adapterpattern;

public interface Turkey {
	public void gobble();
	public void fly();

}
package adapterpattern;

public class WildTurkey implements Turkey {

	@Override
	public void gobble() {
		// TODO Auto-generated method stub
		System.out.println("Gobble gobble");

	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println("I'm flying a short distance");

	}

}
接着要把火鸡类变成鸭子类,那就是引出适配器部分,首先这个适配器要实现目标接口,即Duck接口,并且在该类中以组合形式声明被适配者对象,便于对象的传入,以下是适配器的具体实现。

package adapterpattern;

public class TurkeyAdapter implements Duck {
	Turkey turkey;
	
	public TurkeyAdapter(Turkey turkey)
	{
		this.turkey=turkey;
	}

	@Override
	public void quack() {
		// TODO Auto-generated method stub
		turkey.gobble();

	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		for(int i=0;i<5;i++)
		{
			turkey.fly();
		}

	}

}
        由上面适配器类可以看出,该适配器类实现了Duck接口,并将接口中的quack()方法和fly方法实现,并且将火鸡类中方法在duck类的方法中调用,相当于将火鸡对象的方法进行了封装,外界看到的只是鸭子的方法,实现了指鹿为马的效果。
        接下来是客户端的测试程序:
package adapterpattern;

public class DuckTestDrive {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MallardDuck duck=new MallardDuck();
		WildTurkey turkey=new WildTurkey();
		//将被适配者的对象传入适配器中
		Duck turkeyAdapter=new TurkeyAdapter(turkey);
		
		System.out.println("The Turkey says...");
		turkey.gobble();
		turkey.fly();
		
		System.out.println("\nThe Duck says...");
		testDuck(duck);
		
		System.out.println("\nThe TurkeyAdapter says...");
		testDuck(turkeyAdapter);
		
	}
	static void testDuck(Duck duck)
	{
		duck.quack();
		duck.fly();
	}

}
运行程序,结果如下:
The Turkey says...
Gobble gobble
I'm flying a short distance

The Duck says...
Quack
I'm flying

The TurkeyAdapter says...
Gobble gobble
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
        以上第一个结果是属于火鸡类的结果,第二个结果是鸭子类的结果,第三个是适配器的结果。我们发现适配器的输出结果是表现的火鸡的特征,但它本身属于鸭子类,即鸭子表现出了火鸡的特征。这就是适配器的功能。
        适配器的核心就是适配器实现目标接口,并将被适配者对象传入适配器,并在适配器类中封装被适配者的方法,使其看起来跟目标对象无异,但是内部具体表现却是被适配者的。
        Spring中也有使用到适配器模式的,AOP模式中的 Advice(通知)的类型有:BeforeAdvice、AfterReturningAdvice、ThreowSadvice的。 在每个类型Advice(通知)都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。Spring需要将每个Advice(通知)都封装成对应的拦截器类型,返回给容器,所以需要使用适配器模式对Advice进行转换。在这里,目标对象是对应的拦截器,被适配者是Advice,所以适配器模式可以将Advice封装成对应的拦截器。

        








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值