【设计模式】装饰器模式,很酷炫的样子!

153 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情 >>

引入

玩过足球模拟经营类游戏的朋友,应该了解如何管理球队。其中对球队球员的转会,买入卖出尤其重要。

我们来模拟一下这个场景,球队经理 Manager 需要对球队需要的各类球员进行管理,其中的一环是要分析球员转会市场价,假设不同类型的球员转会费是不同的。

我们抽象出一个 运动员 出来,运动员有各自的计算转会费 TransferFee 的方法;

其中 足球运动员 继承 运动员

开始

球队经理想要了解 足球运动员 的市场价格情况,这一场景我们可以通过如下类图表示:

public class Player {
    public void transferFee() {
        System.out.println("-------综合计算运动员的平均身价-----");
    }
}

class FootballPlayer extends Player {
    @Override
    public void transferFee() {
        System.out.println("------这里是足球运动员的平均身价-----");
    }
}

class GoalFootballPlayer extends FootballPlayer {
    @Override
    public void transferFee() {
        super.transferFee();
        System.out.println("------进球狂魔,这一类球员的身价----------");
    }
}

Manager想要了解足球运动员和进球狂魔运动员分别是多少:

public class Manager {
    public static void main(String[] args) {
        Player player = new GoalFootballPlayer();
        player.transferFee();
    }
}

运行结果:

------这里是足球运动员的平均身价-----
----------进球狂魔这一类球员的身价----------

这个Manager比较有个性,他想要引进 进球多还要长得帅的足球运动员 ,那我们就得再写一个 HandsomeFootballPlayer 继承GoalFootballPlayer

Manager 还不满足,是土豪,想换成 既会进球,又长得帅,护球像亨利的足球运动员 ,这种球员就是大帝,那就再来一个 GodFootballPlayer 继承自 HandsomeFootballPlayer ;

Manager 又有想法了...

如果就这样一直装饰着运动员继承下去,类的数量激增,而且不易维护!!!

在面向对象的设计中,如果超过两层继承,你就应该想想是不是出设计问题了!

那像这种情况我们怎么处理呢?我们分析一下这个场景,会进球长得帅护球像亨利的 足球运动员这些其实都是对 运动员 进行一种 装饰 ,那么我们就可以定义一批专门负责装饰的类,然后根据实际情况来决定是否需要进行装饰。

升级版:

实现(为了方便,类写在同一个文件里了):

/**
 * 足球运动员的装饰器
 * @author 行百里者
 */
public class FootballPlayerDecorator extends Player {
    private Player player;

    public FootballPlayerDecorator(Player player) {
        this.player = player;
    }

    @Override
    public void transferFee() {
        this.player.transferFee();
    }
}

/**
 * 会进球的足球运动员装饰
 */
class GoalFootballPlayerDecorator extends FootballPlayerDecorator {

    public GoalFootballPlayerDecorator(Player player) {
        super(player);
    }

    @Override
    public void transferFee() {
        super.transferFee();
        System.out.println("-------进球狂魔这一类球员的身价y万欧---------");
    }
}

/**
 * 长得帅的足球运动员装饰
 */
class HandsomeFootballPlayerDecorator extends FootballPlayerDecorator {

    public HandsomeFootballPlayerDecorator(Player player) {
        super(player);
    }

    @Override
    public void transferFee() {
        super.transferFee();
        System.out.println("-------长得帅的足球员的身价z万欧---------");
    }
}

/**
 * 足球运动员中的大帝
 */
class GodFootballPlayerDecorator extends FootballPlayerDecorator {

    public GodFootballPlayerDecorator(Player player) {
        super(player);
    }

    @Override
    public void transferFee() {
        super.transferFee();
        System.out.println("-------我的护球像亨利,传说中的大帝,价值 +∞!!! ---------");
    }
}

调用:

public class Manager {
    public static void main(String[] args) {
        // 只看足球运动员
        Player player = new FootballPlayer();
        // 给足球运动员加个会进球的装饰
        player = new GoalFootballPlayerDecorator(player);
        // 再给加个长得帅的装饰
        player = new HandsomeFootballPlayerDecorator(player);
        // 再加个大帝的装饰
        player = new GodFootballPlayerDecorator(player);

        // 看加完装饰后的身价
        player.transferFee();
    }
}

加装饰也可以直接这样调用:

Player player = new GodFootballPlayerDecorator(new GoalFootballPlayerDecorator(new HandsomeFootballPlayerDecorator(new FootballPlayer())));
player.transferFee();

运行结果:

------足球运动员的平均身价x万欧-----
-------进球狂魔这一类球员的身价y万欧---------
-------长得帅的足球员的身价z万欧---------
-------我的护球像亨利,传说中的大帝,价值 +∞!!! ---------

如果我再加其他装饰是不是就很容易了,直接增加装饰类就OK了!这就是 装饰器模式

总结

装饰器模式是对 继承 的有力补充,继承层次太多的话程序就变得不易维护,不好扩展了。

同时,你还要知道继承是静态地给类增加功能,而装饰模式则是动态地增加功能。

在上面的那个例子中,我不想要 GodFootballPlayerDecorator 这层的封装很简单,直接在调用的时候去掉就可以了,如果用继承就必须修改程序。

总之,装饰模式的扩展性非常好,需要用时就赶紧用吧!