携手创作,共同成长!这是我参与「掘金日新计划 · 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
这层的封装很简单,直接在调用的时候去掉就可以了,如果用继承就必须修改程序。
总之,装饰模式的扩展性非常好,需要用时就赶紧用吧!