欢迎来到study-hard-forever的博客

18、桥接模式

桥接模式:

桥接模式(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("请喝一杯茶", "小李");
	}
}
posted @ 2020-06-19 22:17  study-hard-forever  阅读(124)  评论(0编辑  收藏  举报