[置顶] 设计模式(六)桥梁模式
概念
桥梁模式是对象的结构模式,又称为柄体模式或接口模式。桥梁模式的用意是“将抽象化(Abstraction)与实现(Implementation)脱耦,使得二者可以独立的变化”。将两个角色之间的继承关系改为聚合关系,就是将他们之间的强关联改为弱关联,也就是说抽象化和实现之间使用组合/聚合关系而不是继承关系,满足组合/聚合复用原则。
模式结构
两个等级结构
- 抽象化角色和修正抽象化角色组成抽象化等级结构
- 实现角色和具体实现角色组成实现化等级结构
对应角色
- 抽象化角色(Abstraction):抽象化给出的定义,并保存一个对实现化对象的引用
- 修正抽象化角色(RefinedAbstraction):扩展抽象化角色,改变和修正父类对抽象化的定义
- 实现化角色(Implementor):给出实现化角色的接口,但不给出具体的实现。这个角色与抽象化角色给出的接口可以非常不一样
- 具体实现化角色(ConcreteImplementor):给出实现化角色接口的具体实现
抽象化等级结构中的方法通过向对应的实现化对象的委派来实现自己的功能,抽象化角色可以通过向不同的实现化对象委派来动态的转换自己的功能目的。
/** * 抽象化角色:声明了operation方法,并给出了它的实现,该实现是通过向实现化对象的委派(调用operationImpl()方法)实现 */ public abstract class Abstraction { protected Implementor impl; public Abstraction(Implementor impl) { this.impl = impl; } public void operation(){ impl.operationImpl(); } // 其他的操作方法 public void otherOperation(){ } } /** * 修正抽象化角色 */ class RefinedAbstraction extends Abstraction{ public RefinedAbstraction(Implementor impl) { super(impl); } } /** * 实现化角色:实现抽象部分需要的某些具体功能 */ abstract class Implementor{ public abstract void operationImpl(); } /** * 具体实现化A */ class ConcreteImplementorA extends Implementor{ @Override public void operationImpl() { System.out.println("具体实现化A"); } } /** * 具体实现化B */ class ConcreteImplementorB extends Implementor{ @Override public void operationImpl() { System.out.println("具体实现化B"); } } class BridgeClient{ public static void main(String[] args){ Implementor impl = new ConcreteImplementorA(); Abstraction abstraction = new RefinedAbstraction(impl); abstraction.operation(); //把实现方式切换为B调用 impl = new ConcreteImplementorB(); abstraction = new RefinedAbstraction(impl); abstraction.operation(); } }运行结果:
具体实现化A
具体实现化B
抽象化角色的接口比实现化接口角色的接口宽。
示例说明
公司的行政部门有消息需要告知公司同事。需求第一步:通过短信向全体同事发送普同消息;需求第二步:通过短信向部门leader发送紧急消息;需求第三步:通过邮件向全体同事发送普通消息;需求第四步:通过邮件向部门leader发送紧急消息。这样一个需求,从根本上来说分为两个维度:消息类型+发送方式,将来可能还会增加其他类型和方式,必须做到易于扩展。利用桥梁模式解决这一问题。
首先进行等级结构划分
抽象化等级结构:发送消息的方式
实现化等级结构:发送消息的类型
定义实现化接口:发送消息类型
第一步:实现短信方式发送普通消息
/** * 发送消息实现化接口-发送方式 */ interface MessageImplementor{ void send(String message, String toUser); }定义抽象化接口机机器方法
/** * 消息类型抽象化接口:例如:普通消息,紧急消息 */ public abstract class AbstractionMessage { MessageImplementor impl; public AbstractionMessage(MessageImplementor impl) { this.impl = impl; } public void sendMessage(String message, String toUser){ impl.send(message, toUser); } }修正抽象化接口1:普通消息
/** * 发送普通消息-修正消息类型抽象化接口1 */ class CommonMessage extends AbstractionMessage{ public CommonMessage(MessageImplementor impl) { super(impl); } @Override public void sendMessage(String message, String toUser) { super.sendMessage(message, toUser);//普通消息调用父类接口即可 } }具体实现1:短信方式发送
/** * 发送手机短信-实现化接口具体实现1 */ class MessageSMS implements MessageImplementor{ @Override public void send(String message, String toUser) { System.out.println("收到短信消息:"+toUser+","+message); } }
客户端
class MessageClient{ public static void main(String[] args){ MessageImplementor impl = new MessageSMS(); AbstractionMessage message = new CommonMessage(impl); message.sendMessage("今年国庆假期按照国家法定假日休假", "全体同事"); } }发送普通短信消息,运行结果
收到短信消息:全体同事,今年国庆假期按照国家法定假日休假
实现其他类型或方式,只需要增加对应的修正抽象类接口和具体的实现类,客户端进行调用即可,新增加内容与已有内容互相独立,互不影响。
第二步:实现短信方式发送紧急消息
/** * 发送紧急消息-修正消息类型抽象化接口2 */ class UrgencyMessage extends AbstractionMessage{ public UrgencyMessage(MessageImplementor impl) { super(impl); } @Override public void sendMessage(String message, String toUser) { message = "紧急—" + message; super.sendMessage(message, toUser); } //紧急消息在普通消息的基础上增加新功能 public void replyMessage(){ System.out.println("收到紧急消息"); } }增加客户端调用方法
message = new UrgencyMessage(impl); message.sendMessage("本周末召开紧急会议,各部门leader收到请回复", "各部门leader");运行结果:
收到短信消息:全体同事,今年国庆假期按照国家法定假日休假
收到短信消息:各部门leader,紧急—本周末召开紧急会议,各部门leader收到请回复
第三步,第四步:增加邮件方式发送
由于已经实现了发送普通消息和紧急消息的代码,只需要增加邮件方式发送的具体实现,即可同时实现第三四步的需求。
/** * 发送邮件-实现化接口具体实现2 */ class MessageEmail implements MessageImplementor{ @Override public void send(String message, String toUser) { System.out.println("收到邮件消息:"+toUser+","+message); } }客户端代码:
class MessageClient{ public static void main(String[] args){ MessageImplementor impl = new MessageSMS(); AbstractionMessage message = new CommonMessage(impl); message.sendMessage("今年国庆假期按照国家法定假日休假", "全体同事"); message = new UrgencyMessage(impl); message.sendMessage("本周末召开紧急会议,各部门leader收到请回复", "各部门leader"); // 实现方式切换为邮件方式 impl = new MessageEmail(); message = new CommonMessage(impl); message.sendMessage("今年国庆假期按照国家法定假日休假", "全体同事"); message = new UrgencyMessage(impl); message.sendMessage("本周末召开紧急会议,各部门leader收到请回复", "各部门leader"); } }运行结果:
收到短信消息:全体同事,今年国庆假期按照国家法定假日休假
收到短信消息:各部门leader,紧急—本周末召开紧急会议,各部门leader收到请回复
收到邮件消息:全体同事,今年国庆假期按照国家法定假日休假
收到邮件消息:各部门leader,紧急—本周末召开紧急会议,各部门leader收到请回复
桥梁模式解析:通过在不同东西之间搭建一个桥,让它们之间有连接,可以互相通信和使用——为分离的抽象部分和实现部分搭建桥梁。桥接是单向的,只能是抽象部分的对象去使用具体实现的部分对象,不能反着来。如果是一个维度的话用继承直接实现即可,但是两个维度如果用继承(两个维度数相乘)需要实现的类比桥梁方式(两个维度数相加)多。
桥梁模式很好的实现了开闭原则和对用对象组合少用对象继承原则。
桥梁模式优缺点
- 分离抽象和实现:提高系统的灵活性,有助于对系统进行分层。
- 更好的扩展性:抽象和实现分开,并且分别定义了接口,使抽象和实现可以独立的扩展,而互相不影响。
- 动态切换实现:运行期间可以动态的切换实现
- 可减少子类的个数:相对于继承来说,子类数由“乘积”变为“和”
后面几个有点都是基于第一条:分离抽象和实现。