JAVA设计模式:桥接模式
声明:转载请说明来源:http://www.cnblogs.com/pony1223/p/7530721.html
一、引出桥接模式
假设我们现在有一个项目,这个项目列就是我们是生产遥控器的厂商,承接各种遥控器的生产,比如我们现在承接的有LG、索尼的电视厂商的,那如果我们现在要设计的话,我们首先想到的最简单的方式就是如下的方式:
对上述类图作下解释:各大电视机厂商对外提供的一般都是统一接口,以便大家直接操作电视的时候,也就是我们通常如果遥控器丢失的时候,可以直接去按电视机下面的按钮进行直接操作,基本都是一样的,就是因为实现了统一的接口,但因为各自的采用的协议或者算法的不同,因此实现类是不一样的,那么这个时候对于遥控器生产厂商而言要做的,首先要对外是一致的,这样方便操作,但同时又需要去调用各大电视机厂商的实现类,那么最容易的就是继承各个实现类,同时实现自己的接口去做了,于是代码产生如下:
1.电视机厂商的接口:
public interface Control { public void On(); public void Off(); public void setChannel(int ch); public void setVolume(int vol); }
2.LG 索尼公司自己的实现类
package study.designmode.bridgemode.control; public class LGControl implements Control { @Override public void On() { // TODO Auto-generated method stub System.out.println("**Open LG TV**"); } @Override public void Off() { // TODO Auto-generated method stub System.out.println("**Off LG TV**"); } @Override public void setChannel(int ch) { // TODO Auto-generated method stub System.out.println("**The LG TV Channel is setted "+ch+"**"); } @Override public void setVolume(int vol) { // TODO Auto-generated method stub System.out.println("**The LG TV Volume is setted "+vol+"**"); } } package study.designmode.bridgemode.control; public class SonyControl implements Control { @Override public void On() { // TODO Auto-generated method stub System.out.println("*Open Sony TV*"); } @Override public void Off() { // TODO Auto-generated method stub System.out.println("*Off Sony TV*"); } @Override public void setChannel(int ch) { // TODO Auto-generated method stub System.out.println("*The Sony TV Channel is setted "+ch+"*"); } @Override public void setVolume(int vol) { // TODO Auto-generated method stub System.out.println("*The Sony TV Volume is setted "+vol+"*"); } }
3.遥控器厂商的接口
package study.designmode.bridgemode; public interface TvControl { public void Onoff(); public void nextChannel(); public void preChannel(); }
4.实现类:
package study.designmode.bridgemode; import study.designmode.bridgemode.control.LGControl; public class LGTvControl extends LGControl implements TvControl{ private static int ch=0; private static boolean ison=false; public void Onoff() { if(ison) { ison=false; super.Off(); }else{ ison=true; super.On(); } } public void nextChannel() { ch++; super.setChannel(ch); } public void preChannel() { ch--; if(ch<0) { ch=200; } super.setChannel(ch); } }
package study.designmode.bridgemode; import study.designmode.bridgemode.control.SonyControl; public class SonyTvControl extends SonyControl implements TvControl{ private static int ch=0; private static boolean ison=false; public void Onoff() { if(ison) { ison=false; super.Off(); }else{ ison=true; super.On(); } } public void nextChannel() { ch++; super.setChannel(ch); } public void preChannel() { ch--; if(ch<0) { ch=200; } super.setChannel(ch); } }
5.测试:
package study.designmode.bridgemode; public class MainTest { public static void main(String[] args) { LGTvControl mLGTvControl=new LGTvControl(); SonyTvControl mSonyTvControl=new SonyTvControl(); mLGTvControl.Onoff(); mLGTvControl.nextChannel(); mLGTvControl.nextChannel(); mLGTvControl.preChannel(); mLGTvControl.Onoff(); mSonyTvControl.Onoff(); mSonyTvControl.preChannel(); mSonyTvControl.preChannel(); mSonyTvControl.preChannel(); mSonyTvControl.Onoff(); } }
结果:
思考带来的问题:如果我现在要新增承接一个电视厂商夏普的,那么这个时候我需要再实现一个类,然后继承自夏普的实现类,那么带来的问题就是每增加一个电视机厂商的活,那么遥控器厂商就生成一个遥控器的实现类,如果遥控器想要对外界的接口发生以下变化,那么所有的实现类也要变化;也就是遥控器厂商和电视机厂商之间是紧密关联在一起的,没法独立开来,你电视器厂商增加一个,我就要增加一个;拿就是一种N*N的关系,有没有办法做到1*N;就是你电视器厂商的变化,我遥控器厂商不去变化,但可以满足要求,统一一个来实现呢?拿就是桥接模式了。
二、解决办法
要解决上面的问题,首先我们需要分析变化和不变化的部分,上面的需求可以看出,变化的应该是电视机厂商部分,但电视厂商已经统一化了,那么根据以往的经验我们要少用继承,多用组合,如果我们采用组合方式来解决呢,类图如下:
从上述可以看出,满足了我们的1*n的想法,这也桥接模式的意义所在。
桥接模式:将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变。(这里的抽象就是我们遥控器厂商,实现就是我们的电视机厂商)
代码实现如下:
1.抽象类
package study.designmode.bridgemode.bridge; import study.designmode.bridgemode.control.Control; public abstract class TvControlabs { Control mControl=null; public TvControlabs(Control mControl) { this.mControl=mControl; } public abstract void Onoff(); public abstract void nextChannel(); public abstract void preChannel(); }
2.实现类:
package study.designmode.bridgemode.bridge; import study.designmode.bridgemode.control.Control; public class TvControl extends TvControlabs { private int ch=0; private boolean ison=false; public TvControl(Control mControl) { super(mControl); } @Override public void Onoff() { // TODO Auto-generated method stub if(ison) { ison=false; mControl.Off(); }else{ ison=true; mControl.On(); } } @Override public void nextChannel() { // TODO Auto-generated method stub ch++; mControl.setChannel(ch); } @Override public void preChannel() { // TODO Auto-generated method stub ch--; if(ch<0) { ch=200; } mControl.setChannel(ch); } }
3.测试:
package study.designmode.bridgemode.bridge; import study.designmode.bridgemode.control.LGControl; import study.designmode.bridgemode.control.SharpControl; import study.designmode.bridgemode.control.SonyControl; public class MainTest { public static void main(String[] args) { TvControl mLGTvControl; TvControl mSonyTvControl; mSonyTvControl=new TvControl(new SonyControl()); mLGTvControl=new TvControl(new LGControl()); mLGTvControl.Onoff(); mLGTvControl.nextChannel(); mLGTvControl.nextChannel(); mLGTvControl.preChannel(); mLGTvControl.Onoff(); mSonyTvControl.Onoff(); mSonyTvControl.preChannel(); mSonyTvControl.preChannel(); mSonyTvControl.preChannel(); mSonyTvControl.Onoff(); /* newTvControl mSharpTvControl; mSharpTvControl=new newTvControl(new SharpControl()); mSharpTvControl.Onoff(); mSharpTvControl.nextChannel(); mSharpTvControl.setChannel(9); mSharpTvControl.setChannel(28); mSharpTvControl.Back(); mSharpTvControl.Onoff();*/ } }
三、总结
当系统有多维度角度分类的时候,而每一种分类又有可能的变化,考虑使用桥接模式。桥接的目的是分离抽象与实现,使抽象和实现可以独立变化。
和策略模式的差异:
桥接的目的是让底层实现和上层接口可以分别演化,从而提高移植性
策略的目的是将复杂的算法封装起来,从而便于替换不同的算法。
桥接是往往是为了利用已有的方法或类
策略是为了扩展和修改,并提供动态配置
桥接强调接口对象仅仅提供基本的操作
策略强调接口对象提供的是这一种算法