装饰者模式与MyBatis二级缓存中装饰者模式的使用

一、什么是装饰者模式

       装饰者模式的定义是 动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。

        在设计的时候,往往要给一个对象的功能进行一些修饰,对功能进行拓展和增强,以满足我们的需求。

二、装饰者模式的作用

        比如我们现在有一个歌手大赛,所有的歌手都需要去唱歌。但是每一个歌手需要不一样的舞台特效,我们可提供的舞台特效有:伴舞,伴乐,背景大屏幕等。比如A歌手需要伴舞,B歌手需要伴奏,C歌手需要伴奏和伴舞,D歌手需要伴奏和背景大屏等等。有很多个歌手,有很多个需求。 我们一般性地算一下,如果有不同的装饰功能 N 个,那么,如果我们将这N个随机组合,将有:

         

种可能,如果不使用装饰者模式,我们需要对每一个歌手进行个性化定制。并且代码的重复度很高(这一点会在第三部分代码部分说明)。因此我们使用装饰者模式,这种模式灵活使用了继承与多态。具体内容将会在下面的部分以代码的形式展现。

三、如果没有装饰者模式

       下面我们用代码来演示上面的例子

       首先所有的歌手都需要唱歌,因此我们需要一个歌手

public class Competitor {
    public void sing() {
        System.out.println("我唱唱唱......");
    }
}
      然后有一名歌手需要伴舞

class DanceCompetitor extends Competitor{

    //dance方法
    public void dance(){
        System.out.println("打开微信跳一跳 ---- 我蹦,我蹦!");
    }

    // sing方法,对sing方法进行改造,使其既可以sing也可以dance
    @Override
    public void sing(){
        super.sing();
        dance();
    }
    
}
    又有一名歌手需要伴乐

class MusicCompetitor extends Competitor{

    //dance方法
    public void music(){
        System.out.println("我拨片呢! 大哥要开始疯狂扫弦了 !! ---- ");
    }

    // sing方法,对sing方法进行改造,使其既可以sing也可以dance
    @Override
    public void sing(){
        super.sing();
        music();
    }

}
    现在又有一个歌手需要观众鼓掌
class ApplauseCompetitor extends Competitor{

    //dance方法
    public void applause(){
        System.out.println("啪啪啪 !!啪啪啪!!啪!啊!!!啊  ----  不要误会,鼓掌之后需要尖叫的");
    }

    // sing方法,对sing方法进行改造,使其既可以sing也可以dance
    @Override
    public void sing(){
        super.sing();
        applause();
    }

}

是不是看起来很清晰?但是现在又有一个问题,如果一个歌手又需要伴舞又需要伴乐又需要观众鼓掌怎么办呢??


class AllCompetitor extends Competitor{

    ApplauseCompetitor applauseCompetitor = new ApplauseCompetitor();
    MusicCompetitor musicCompetitor = new MusicCompetitor();
    DanceCompetitor danceCompetitor = new DanceCompetitor();

    public void all(){
        applauseCompetitor.applause();
        musicCompetitor.music();
        danceCompetitor.dance();
    }

    @Override
    public void sing(){
        super.sing();
        all();
    }

}

    现有一名歌手只需要伴乐和伴舞呢......

    代码会有会多重复的调用,而且需求增加,我们就需要多创建一个类,冗余很大,侵入很强。那怎么办呢?使用装饰者模式就  可以解决这样的问题

四、使用装饰者模式的实例

鼓掌类:我们需要继承与基础的那个唱歌的方法,同时使用组合,在内部保有一个super class。同时提供一个有参的构造方法。

public class CompetitorApplause extends Competitor{

    private Competitor competitor;

    public CompetitorApplause(Competitor competitor){
        this.competitor = competitor;
    }

    public void sing(){
        applause();
        competitor.sing();
    }

    public void applause(){
        System.out.println("啪啪啪!!啪啪啪!!!");
    }
}
同样的我们定义跳舞和伴乐

public class CompetitorDance extends Competitor{

    private Competitor competitor;

    public CompetitorDance(Competitor competitor){
        this.competitor = competitor;
    }

    public void sing(){
        dance();
        competitor.sing();
    }

    public void dance(){
        System.out.println("dancing");
    }
}

伴乐

public class CompetitorMusic extends Competitor{
    private Competitor competitor;

    public CompetitorMusic(Competitor competitor){
        this.competitor = competitor;
    }

    public void sing(){
        music();
        competitor.sing();
    }

    public void music(){
        System.out.println("music!!!!");
    }
}

看上去没有什么太大的不同?事实上,装饰者模式灵活的使用了继承和多态,来使我们的系统很好的解耦。我们内部保有一个父类的对象以后,子类的构造方法需要提供一个父类。而我们构造子类的时候可以提供一个其他的子类给这个子类,这个子类在调用本身保有的那个父类的sing()时,其实是调用了入参的子类的sing();因此我们可以根据不同的业务,不同的条件,让系统去组成不一样的定制化的歌手,这样就尽量少的对系统进行改动,也很大的减少了代码的冗余。

测试方法如下

public class decorationTest {
    @Test
    public void testA(){
        Competitor competitor = new Competitor();

        CompetitorMusic competitorMusic = new CompetitorMusic(competitor);

        CompetitorDance competitorDance = new CompetitorDance(competitorMusic);

        CompetitorApplause competitorApplause = new CompetitorApplause(competitorDance);

        competitorApplause.sing();
    }

    @Test
    public void testWithBusiness(){
        Competitor competitor = new Competitor();

        int a = 10;

        //做业务判断
        if( a == 10 ){ competitor = new CompetitorMusic(competitor); }

        if( a > 35) { competitor = new CompetitorApplause(competitor); }

        if( a < 50 ){ competitor = new CompetitorDance(competitor); }

        competitor.sing();
    }
}

五、Mybatis二级缓存中装饰者模式的使用

 Mybatis中,其二级缓存机制使用了装饰者模式。他根据配置文件中读取的不同信息,而动态的生成不一样类型的Cache。具体类图如下

装饰者模式与MyBatis二级缓存中装饰者模式的使用_第1张图片

一个Cache的父类,拥有很多子类,我们根据不同的业务,去装饰Cache的父类,得到不同的Cache方式。

具体对装饰者模式的使用的代码如下:

  private Cache setStandardDecorators(Cache cache) {
    try {
      MetaObject metaCache = SystemMetaObject.forObject(cache);
      if (size != null && metaCache.hasSetter("size")) {
        metaCache.setValue("size", size);
      }
      if (clearInterval != null) {
        cache = new ScheduledCache(cache);
        ((ScheduledCache) cache).setClearInterval(clearInterval);
      }
      if (readWrite) {
        cache = new SerializedCache(cache);
      }
      cache = new LoggingCache(cache);
      cache = new SynchronizedCache(cache);
      if (blocking) {
        cache = new BlockingCache(cache);
      }
      return cache;
    } catch (Exception e) {
      throw new CacheException("Error building standard cache decorators.  Cause: " + e, e);
    }
  }
是不是很清晰明了呢?

你可能感兴趣的:(设计模式)