• Java设计模式系列之桥接模式


    桥接模式(Bridge)的定义

    在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?这就要使用桥接模式

    将抽象部分与它的实现部分分离,使它们都可以独立地变化。

    桥接模式(Bridge)的动机

    当一种抽象类型可能有多种实现方式时,一般情况我们可以考虑使用继承来解决抽象类型的多种实现,在抽象类型中定义接口,而子类负责接口的具体实现。但这种做法缺乏灵活性,由于抽象类型和子类之间紧紧地绑定在一起,使得这种关系在运行时不能再修改,这使得它难以修改、扩展和重用不利于抽象和实现解耦,而且这也违背OOP原则:“优先使用对象聚集,而不是继承”。这种思想是桥接模式的精髓所在。

    桥接模式(Bridge)的UML类图

                                      

    桥接模式(Bridge)的参与者

        1.Abstraction

          定义抽象类的接口。

          维护一个指向Implementor类型对象的指针。

        2.RefinedAbstraction

          扩充由Abstraction定义的接口。

        3.Implementor

          定义实现类的接口,该接口不一定要与Abstraction的接口完全一致。

          事实上这两个接口可以完全不同。

          一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。

        4.ConcreteImplementor

          实现Implementor接口并定义它的具体实现。

    在这里用尚学堂马士兵老师的一个例子来讲解一下桥接设计模式:追MM的技术

    第一步:我们追MM,首先要有一个类,来封装MM,类中包括MM的属性姓名;

    public class MM {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        
    }

    第二步:用一个类来封装男主人公,里面包含他的一些属性和方法

    public class Boy {
    
        private String name;
    
        //也可以把mm放在这个位置,但是坚持高聚合,低耦合,则放到参数的位置
        //    MM mm;
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        //追MM
        public void pursue(MM mm){
        }
        //给MM送礼物,礼物有分类
        public void give(Gift g,MM mm){
            
        }
    }

    第三步:根据方法中的参数类型,我们还需要定义一个Gift类,来代表礼物,类里面暂时什么也没有添加

    public class Gift {
    }

    接着我们定义具体的礼物(Flower、Ring之类的东西),在这里我们思考一个问题,可以考虑将这两个具体的礼物类(Flower和Ring)去继承Gift,但是这样的话,基类Gift和子类之间的耦合行太强,基类一旦改变,子类也要发生改变,所以在这里我们用组合来代替继承(组合就是一个类中包含另外一个类的对象的引用)
    我们暂时先这样定义两个具体类:

     public class Ring{
         
     }
     public class Flower{
         
     }

    但是礼物也分很多种分类,比如说温暖的(warm)、冷酷的(cold)、狂野的(wild),这些是我们概念上的分类,这三种修饰词和前面的两个具体类(我们的具体实现)存在排列组合的问题(因为出现了交叉),我们可以针对不同类别的MM送不同组合的礼物,比如温暖的花送温柔的MM,酷酷的戒指送高冷的MM等等。这样的话就出现了我们前面说过的问题,礼物Gift这一类型它存在两个维度的变化,它可以是温暖的、冷酷的、狂野的,也可以是具体的Flower、Ring

    我们先把上面的三种分类定义出来:

     public class WarmGift extends Gift{
     }
     public class WildGift extends Gift {
     }
     public class ColdGift extends Gift{
     }

    我们如果要送温暖的花这种礼物应该怎么做?有一张想法是以Flower为基类,定义一个WarmFlower继承Flower,这样也可以,但是这样的话由于礼物种类的纷杂,会产生层出不穷的子类,比如WarmRing、ColdRing等等。
    那我们应该怎么做呢?

    在这里我们定义一个类GiftImpl,具体的礼物实现,具体的礼物Flower和Ring继承自GiftImpl,而让礼物的分类WarmGift、ColdGift、WildGift,继承自Gift,让Gift类内包含一个GiftImpl的引用

    public class Gift {
        protected GiftImpl impl;
    }
    public class WildGift extends Gift {
        public WildGift(GiftImpl impl){
            this.impl=impl;
        }
    }
    public class WarmGift extends Gift{
        //WarmGift继承自Gift,也继承了那个GiftImpl对象引用
        public WarmGift(GiftImpl impl){
            this.impl=impl;
        }
    }

    我们定义抽象类GiftImpl,定义基本的操作

    public abstract class GiftImpl {
        public abstract String giftMessage();
    }

    Flower和Ring类去继承抽象类GiftImpl

      public class Flower extends GiftImpl{
      
          public String giftMessage() {
              
              return "鲜花";
          }
      }
      public class Ring extends GiftImpl{
      
         public String giftMessage() {
             
             return "戒指";
         }
      }

    第四步:我们的Boy类中,男主人公就可以送不同组合的礼物了。

         //追MM
         public void  pursue(MM mm){
             //我们送的是温暖的花
             Gift g=new WarmGift(new Flower());
             give(g, mm);
             //送给MM的是狂野的戒指
             g=new WildGift(new Ring());
             give(g, mm);
         }

     我们下面再举一个例子,包含完整的代码以及测试结果,这个例子简而言之就是"人穿裤子"。

    男人穿马甲

    男人穿裤子

    女人穿马甲

    女人穿裤子

    我们按照桥接模式的四个参与对象来实现我们的组合输出

    第一步:定义Abstraction

    //定义Abstraction 
    public abstract class Person {
        //包含两个属性,男人还是女人,穿的衣服的种类
        private Clothing clothing;
        private String type;
        public Clothing getClothing() {
            return clothing;
        }
        public void setClothing(Clothing clothing) {
            this.clothing = clothing;
        }
        public String getType() {
            return type;
        }
        public void setType(String type) {
            this.type = type;
        }
        public abstract void dress();
    }

    第二步:定义RefinedAbstraction 

    class Man extends Person {
    
        public Man(){
            setType("男人");
        }
        //dress方法定义男、女和衣服的排列组合
        public void dress() {
              Clothing clothing = getClothing();
              clothing.personDressCloth(this);
        }
    
    }
    class Women extends Person {
    
        public Women(){
            setType("女人");
        }
        //dress方法定义男、女和衣服的排列组合
        public void dress() {
              Clothing clothing = getClothing();
              clothing.personDressCloth(this);
        }
    
    }

    第三步:定义Implementor

     public abstract class Clothing {
     
         public void personDressCloth(Person person); 
     }

    第四步:定义ConcreteImplementor

    class Pants extends Clothing{
    
        public void personDressCloth(Person person) {
            System.out.println(person.getType() + "穿裤子");
        }
        
    }
    class Jacket extends Clothing{
    
        public void personDressCloth(Person person) {
            System.out.println(person.getType() + "穿马甲");
        }
        
    }

    第五步:写个测试类

    public class BridgeTest {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            Person man=new Man();
            Person women=new Women();
            Clothing jacket=new Jacket();
            Clothing pants=new Pants();
            //男人穿马甲
            jacket.personDressCloth(man);
            //女人穿马甲
            jacket.personDressCloth(women);
            //男人穿裤子
            pants.personDressCloth(man);
            //女人穿裤子
            pants.personDressCloth(women);        
        }
    }
  • 相关阅读:
    iOS之MRC和ARC
    给tableView的cell上加长按转发,复制、、等功能
    时间格式相关
    Xcode7,消失的pin菜单(Editor->pin)
    UIView常用的一些方法小记之setNeedsDisplay和setNeedsLayout
    监听iPhone的通话状态之---CoreTelephony.framework
    iOS中一些系统通知名字集合
    iOS中的程序的五种状态
    Objective-C基础之@synthesize, @dynamic
    Objective-C基础之category extension
  • 原文地址:https://www.cnblogs.com/ysw-go/p/5408469.html
Copyright © 2020-2023  润新知