策略模式 VS 桥梁模式
这对冤家终于碰头了,策略模式与桥梁模式是如此相似,简直就是孪生兄弟,要把它们两个分开需要花费大量智力,我们来看看两者的通用类图,如下所示。
?
?
我们定义了一个邮件模版,它有两个实现类:TextMail(文本邮件)和HtmlMail(超文本邮件),分别实现两种不同格式的邮件封装。MailServer是一个环境角色,它接受一个MailTemplate对象,然后通过sendMail方法发送出去。我们来看具体的代码,先看抽象邮件,如下所示。
?
?
?我们覆写了getContext方法,因为要把一封邮件设置为文本邮件必须加上一个特殊的标志:text/plain,这句话是告诉解析这份邮件的客户端:“我是一封文本格式的邮件,别解析错了”。同样,超文本格式的邮件也有类似的设置,如下所示。
?
?
?很简单,邮件服务器接受了一封邮件,然后调用自己的发送程序进行发送。可能各位读者要提问了,为什么不把sendMail方法移植到邮件模板类中呢?这也是邮件模板类的一个行为呀,邮件可以被发送,是的,确实是邮件的一个行为,完全可以这样做,两者没有什么特别的区别,只是从不同的角度看待该方法而已。我们继续看场景类,如下所示。
?
?该类相对于策略模式的环境角色有两个改变:
?为什么要覆写sendMail程序呢?是因为每个邮件服务器在发送邮件时都会在邮件内容上留下自己的标志,一是广告作用,二是方便互联网上统计需要,三是方便同质软件的共振。我们再来看SendMail邮件服务的实现,如下所示。
?
public class Client {public static void main(String[] args) {//创建一封TEXT格式的邮件MailTemplate m = new HtmlMail("a@a.com","b@b.com","外星人攻击地球了","结局是外星人被中国人熬汤炖着吃了!");//使用postfix发送邮件MailServer mail = new Postfix(m);//发送邮件mail.sendMail();}}?运行结果如下所示:
====正在发送的邮件信息====
发件人:a@a.com
收件人:b@b.com
邮件标题:外星人攻击地球了
邮件内容:
Content-Type: multipart/mixed;charset=GB2312
Received: from XXXX (unknown [xxx.xxx.xxx.xxx]) byaaa.aaa.com (Postfix) with ESMTP id 8DBCD172B8
结局是外星人被中国人熬汤炖着吃了!
邮件格式为:超文本格式
当然了,还有其他三种发送邮件的方式:Postfix发送文本邮件,SendMail发送文本邮件和超文本邮件,修改很小,读者可以自行修改实现,体现一下桥梁模式的不同点。
?
小结
策略模式和桥梁模式是如此相似,我们只能从它们的意图上来分析,策略模式是一个行为模式,旨在封装一系列的行为,在例子中我们认为把邮件的必要信息(发件人、收件人、标题、内容)封装成一个对象就是一个行为,封装的格式(算法)不同,行为也就不同。而桥梁模式则是解决在不破坏封装的情况下如何抽取出它的抽象部分和实现部分,它的前提是不破坏封装,让抽象部分和实现部分都可以独立地变化,在例子中,我们的邮件服务器和邮件模版是不是都可以独立地变化?不管是邮件服务器还是邮件模板,只要继承了抽象类就可以继续扩展,它的主旨是建立一个不破坏封装性的可扩展架构。
精简地来说,策略模式是使用继承和多态建立一套可以自由切换算法的模式,桥梁模式是在不破坏封装的前提下解决抽象和实现都可以独立扩展的模式。
还是很难区分,是吧?多想想他们两者的意图,就可以理解为什么要建立两个相似的模式了。不要太多考虑它们之间的区别了,使用才是正道,我们在做系统设计时,可以不考虑到底使用的是策略模式还是桥梁模式,只要好用,能够解决问题就成,“不管黑猫白猫,抓住老鼠的就是好猫”。
?
设计模式有什么不明白的地方,可以到我的博客上查找或讨论:http://hi.baidu.com/cbf4life
1 楼 Durian 2009-12-10 呵呵,我现在还分不清他们哥俩。
感谢楼主写此文章与我解惑。 2 楼 329087553 2009-12-19 学习了,感谢楼主分享!