桥接模式:
桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们都可以独立地变化。(实现系统可能有多角度分类,每一种分类都有可能变化(只用继承会造成类的大量增加,不能满足开放——封闭原则),那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合)
抽象与它的实现分离,并不是说让抽象类与其派生类分离,实现指的是抽象类和它的派生类用来实现自己的对象。例:手机既可以按照品牌来分类,也可以按照功能来分类,具体可以参考下面实例:
按品牌分类:
按软件实现分类:
由于实现的方式有多种,桥接模式的核心意图就是把这些实现独立出来,让他们各自地变化,这就使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。
桥接模式实现:
这样就解决了按品牌分类或按软件分类增加新品牌/软件时的复杂性和代码不可复用性。
桥接模式UML结构图:
例(手机软件):
//手机品牌
abstract class HandsetBrand
{
protected HandsetSoft soft;
//设置手机软件
public void SetHandsetSoft(HandsetSoft soft)
{
this.soft = soft;
}
//运行
public abstract void Run();
}
//手机品牌N
class HandsetBrandN : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
//手机品牌M
class HandsetBrandM : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
//手机品牌S
class HandsetBrandS : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
//手机软件
abstract class HandsetSoft
{
public abstract void Run();
}
//手机游戏
class HandsetGame : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行手机游戏");
}
}
//手机通讯录
class HandsetAddressList : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行手机通讯录");
}
}
//手机MP3播放
class HandsetMP3 : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行手机MP3播放");
}
}
class Program
{
static void Main(string[] args)
{
HandsetBrand ab;
ab = new HandsetBrandN();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAddressList());
ab.Run();
ab = new HandsetBrandM();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAddressList());
ab.Run();
Console.Read();
}
}
例(发送提示消息):
消息分成普通消息、加急消息和特急消息多种,不同的消息类型,业务功能处理是不一样的,比如加急消息是在消息上添加加急,而特急消息除了添加特急外,还会做一条催促的记录,多久不完成会继续催促。从发送消息的手段上看,又有系统内短消息、手机短消息、邮件等等。
全部采用继承,不使用桥接模式的UML图(如果继续扩展消息类型或者发送方式将会十分繁琐):
例:继续添加发送手机消息的处理方式(这个时候代码结构就逐渐开始变得复杂):
桥接模式实现:
代码:
public interface MessageImplementor {
public void send(String message,String toUser);
}
public class MessageEmail implements MessageImplementor {
public void send(String message, String toUser) {
System.out.println("使用Email的方式,发送消息'" + message + "'给" + toUser);
}
}
public class MessageMobile implements MessageImplementor {
public void send(String message, String toUser) {
System.out.println("使用手机短消息的方式,发送消息'" + message + "'给" + toUser);
}
}
public class MessageSMS implements MessageImplementor {
public void send(String message, String toUser) {
System.out.println("使用站内短消息的方式,发送消息'" + message + "'给" + toUser);
}
}
public abstract class AbstractMessage {
protected MessageImplementor impl;
public AbstractMessage(MessageImplementor impl) {
this.impl = impl;
}
public void sendMessage(String message, String toUser) {
this.impl.send(message, toUser);
}
}
public class CommonMessage extends AbstractMessage {
public CommonMessage(MessageImplementor impl) {
super(impl);
}
public void sendMessage(String message, String toUser) {
super.sendMessage(message, toUser);
}
}
public class UrgencyMessage extends AbstractMessage {
public UrgencyMessage(MessageImplementor impl) {
super(impl);
}
public void sendMessage(String message, String toUser) {
message = "加急:" + message;
super.sendMessage(message, toUser);
}
public Object watch(String messageId) {
return null;
}
}
public class SpecialUrgencyMessage extends AbstractMessage {
public SpecialUrgencyMessage(MessageImplementor impl) {
super(impl);
}
public void hurry(String messageId) {
// 执行催促的业务,发出催促的信息
}
public void sendMessage(String message, String toUser) {
message = "特急:" + message;
super.sendMessage(message, toUser);
}
}
/* * 意图:将抽象部分与实现部分分离,使它们都可以独立的变化。 * 主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。 * 何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。 * 如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。 * 关键代码:抽象类依赖实现类。 */
/* * 该发送消息的实例由于发送方式的可扩展性和发送级别(普通,加急,特急等)的可扩展性,使用继承并不灵活 * 考虑使用桥接模式:分离这两部分,使它们独立变化,减少它们之间的耦合(低耦合) * 注意事项:有时候我们看待问题的角度不同,可能采取的分离措施也会有所不同,因此代码结构也会有所不同 *(这种过于复杂的情况下桥接模式就不再能说很合适,因为桥接模式本身就加剧了代码的复杂性,较于继承更加难以理解一些,但是使用得当则会让代码结构更加简洁清晰) */
public class Client {
public static void main(String[] args) {
MessageImplementor impl = new MessageSMS(); //接口下的发送方式定义
AbstractMessage m = new CommonMessage(impl); //发送消息的方式实现
m.sendMessage("请喝一杯茶", "小李");
m = new UrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
m = new SpecialUrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
impl = new MessageMobile();
m = new CommonMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
m = new UrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
m = new SpecialUrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
impl = new MessageEmail();
m = new CommonMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
m = new UrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
m = new SpecialUrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
}
}