这段时间做项目,需要用到多种设计模式的结合,之前菜菜本人只用过简单工厂和单态模式,于是又抓紧多学了些,以下,菜菜将就Bridge pattern和Strategy pattern两者的比较,来一起学习一下这两个模式。
在具体给出两者具体异同点、优缺点之前,给出一下文档给的定义:
桥接模式:一种结构模式(牛郎织女本在一起,将牛郎和织女分开,中间搭一座桥)
策略模式:一种行为模式(将各种算法封装,用户可随意挑选需要的算法)
下面分开讲解,我们先来看一下Bridge模式的模型:
从UML图中,可以很容易看出桥接模式的参与者主要有:
抽象类,扩充抽象类,实现类,具体实现类。 具体每个参与对象的概念在这里就不详细解决,不理解的童鞋可以去百度一下,很多,主要说一下这几个参与对象在Bridge模式中是如何进行协调工作,达到什么样的功效,稍后给出各部分代码。
在Bridge模式中,要理解“桥接”这个概念,在上面描述的四个参与者中,从字面可以看出分为抽象部分和实现部分,那么桥接的发生,自然是发生在这两者之间,即桥接抽象部分与实现部分。起桥接作用的是扩充抽象类,而且,大家记住了,在桥接模式中,桥接是“单向桥”,即只能由抽象部分的对象去使用具体实现部分的对象。
桥接模式的意图:使得抽象和实现部分都能独立变化,达到可扩充性。可以理解为,抽象部分和实现部分其实是在某种程度上是独立的,只不过抽象部分用了实现部分对外的接口而已。
好了,假设有这么一个案例,菜菜想请人陪自己娱乐,如果是猫猫来了要看电影呢,他俩就去影院;如果是公猫来了要吃大餐呢,他俩就去西餐厅,用桥接模式,就这样实现:
抽象类:
- /*
- * 抽象部分Abstraction
- */
- public abstract class EngagedAbstraction {
- public abstract void getReady(Plan plan);
- }
扩充抽象类:
- /*
- * 抽象实现部分(扩充抽象)
- */
- public class Caicai extends EngagedAbstraction{
- public void getReady(Plan paln) {
- // TODO Auto-generated method stub
- System.out.print("菜菜同"+paln.getName());
- if(paln.getplanName().equals( "eat")) {
- System.out.println("去西餐厅"+paln.getplanName());
- }
- else
- System.out.println("去影院"+paln.getplanName());
- }
- }
实现类接口(在这里菜菜就还是用抽象类写了,用Interface一样的)
- /*
- * 实现类接口
- */
- public abstract class Plan {
- // 很少用JAVA的get与Set方法,试一下,大家也可以直接用变量测试和熟悉该模式
- protected String name;
- public void setName(String name){
- this.name = name;
- }
- public String getName(){
- return this.name;
- }
- protected String planName;
- public void setplanName(String name){
- this.planName = name;
- }
- public String getplanName(){
- return this.planName;
- }
- public abstract void bringUp(String planName);
- }
具体实现类(就是实现类接口的实现,有点绕口)
- /*
- * 具体实现类
- */
- public class Mao extends Plan {
- public void bringUp(String planName) {
- // TODO Auto-generated method stub
- setplanName(planName);
- }
- public String getName() {
- // TODO Auto-generated method stub
- return super.getName();
- }
- public String getplanName() {
- // TODO Auto-generated method stub
- return super.getplanName();
- }
- public void setName(String name) {
- // TODO Auto-generated method stub
- super.setName(name);
- }
- public void setplanName(String name) {
- // TODO Auto-generated method stub
- super.setplanName(name);
- }
- }
下面就是客户端测试类:
- /*
- * 客户端测试类
- */
- public class Client {
- public static void main(String[] args)
- {
- Plan gongMao=new Mao();
- gongMao.setName("公猫");
- gongMao.bringUp("eat");
- Plan muMao=new Mao();
- muMao.setName("猫");
- muMao.bringUp("watch film");
- Caicai man=new Caicai();
- man.getReady(gongMao);
- man.getReady(muMao);
- }
- }
运行结果:
- 菜菜同公猫去西餐厅eat
- 菜菜同猫去影院watch film
为什么需要这么设计呢? 现在设想一种情况,菜菜找人娱乐的方式多了,不只是影院和西餐厅,还想去步行街。 而猫的伙伴多了,来了大脸猫,它还想要要逛街(或者菜菜想陪公猫去影院,和猫去西餐厅喝酒),就是说,抽象部分和实现部分都需要发生变化(其实这两者可以独立变化,不对对方产生影响),那么用上面的桥接模式,就很简单了,哪部分需求变了就改哪一部分,客户端根本不知道,即保证了扩充性,又保证了对客户的透明性。
理解了吗,各位,下面让我们看看Strategy(策略模式),说简单一点,策略模式在形式上,或者说在代码结构上,少了那个桥接部分(也就是扩充抽象类)。当然了,这样一个说法,是让大家先提前在脑子里面有个策略模式的大体UML模型。
直接上代码啦:
策略的接口(或者抽象类)
- //抽象的策略角色(也可以是接口,和Bridge模式同理)
- public abstract class Caicai {
- public abstract void operate();
- }
策略的实现(只写了两个策略,一个去影院,一个去餐厅)
- /*
- * 策略的实现,去影院的策略
- */
- public class Cinema extends Caicai{
- public void operate(){
- System.out.println("菜菜和公猫去影院");
- }
- }
- /*
- * 策略的实现,去餐厅的策略
- */
- public class Resturant extends Caicai{
- public void operate(){
- System.out.println("菜菜和猫去餐厅");
- }
- }
上下文(Context)
- /*
- * 上下文
- */
- public class Context {
- private Caicai strategy;
- //构造函数,选择哪一个策略
- public Context(Caicai strategy){
- this.strategy = strategy;
- }
- public void operate(){
- this.strategy.operate();
- }
- }
客户端程序
- /*
- * 客户端程序
- */
- public class Client {
- public static void main(String[] args) {
- Context context;
- context=new Context(new Resturant());
- context.operate();
- context=new Context(new Cinema());
- context.operate();
- }
- }
运行结果
- 菜菜和猫去餐厅
- 菜菜和公猫去影院
OK,代码完成了,写的虽然是最简单的策略模式,但是相信也是最容易让大家理解的。 和桥接模式从代码结构看,少了扩充抽象类,把抽象类改成了上下文(Context),即策略的决定者。
看完代码,经过菜菜粗略的介绍,相信大家在心里对策略模式有了一点点了解了吧,下面,再啰嗦一下策略模式的定义,到最后再比较它和桥接模式。
策略模式:又称为算法簇模式。从以上代码的策略实现类,可以看出,每一个实现类都封装了一种变化。于是,采用策略模式可以根据用户不同配置,选择相应的算法,可以避免条件语句带来的代码混乱,提高代码的可读性和程序的灵活性。
现在菜菜和大家一起学习了一遍bridge和strategy两个模式(在写文章的时候才忘记策略模式的demo忘写了,刚补起来呢),那么它们各自有哪些优缺点呢? 在这里,菜菜把自己查到的一些资料上讲述的,和大家分享一下,大家有什么更好的想法或者资料,欢迎交流。
优点和相同点:都很好的体现了面向对象的思想(封装变化),体现了设计模式的精髓(替代继承关系),都在某种程度上体现了独立性(可扩展性),都是 环境(上下文)/扩充抽象类 来决定策略/具体实现
缺点和不同点:策略模式的客户端需要知道所有策略类,才能选择;策略模式可能会出现很多策略类,导致程序的臃肿
桥接模式和策略模式的主要差别是目的不一样,策略模式的目的是封装算法,使得算法可以相互替换;而桥接的目的是分离抽象与实现,使抽象和实现可以独立变化。
好啦,真累,讲完了,自己又有一种不知所云的感觉了,希望不要把本来已经理解的同志给搞迷糊了。 策略模式讲的少一点,因为是今天下午才看的,嘿嘿,见谅哇。。 尽情拍砖。