从王者荣耀看设计模式(装饰者模式)
一.简介
王者荣耀中,角色的"伤害值"和"生命值"是很重要的概念。为了保证游戏的胜利,玩家会通过在游戏开始前配置合适的游戏铭文,在游戏中积累经济购买装备的方式来提升英雄角色的伤害值和生命值。
二.装饰者模式
装饰者模式(Decorator Pattern)是一种比较常见的模式,装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案
模式动机
在现实生活中,在不改变一个对象本身的基础上给对象增加额外的新行为的情况比比皆是。在本实例中,给英雄装饰各类装备可以增加英雄的生命值和攻击力。
-
装饰者模式的使用场景
- 需要扩展一个类的功能,或给一个类增加附加功能
- 需要动态地给一个对象增加功能,这些功能可以再动态地撤销
- 需要为一批的兄弟类进行改装或加装功能,当然首选装饰者模式
- 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时(1.1 系统中存在大量独立的扩展,为支持每一种组合将产生大量子类,使得子类的数量呈爆炸性增长; 2.2 类定义不能继承(final类))
-
装饰者模式涉及的设计原则有:
- 装饰者(decorator)和被装饰(扩展)的对象有着相同的超类(supertype)
- 我们可以用多个装饰者去装饰一个对象。
- 我们可以用装饰过的对象替换代码中的原对象,而不会出问题(因为他们有相同的超类)。
- 装饰者可以在委托(delegate,即调用被装饰的类的成员完成一些工作)被装饰者的行为完成之前或之后加上他自己的行为。
- 一个对象能在任何时候被装饰,甚至是运行时。
-
装饰者模式的通用类图:
-
装饰者模式所涉及的角色有:
● Component抽象构件:Component是一个接口或者是一个抽象类,就是定义我们最核心的对象,也就是最原始的对象(在装饰模式中,必然有一个最基本,最核心,最原始的接口或抽象类充当Component抽象构件)。
● ConcreteComponent具体构件:ConcreteComponent是最核心,最原始,最基本的接口或抽象类的实现,你要装饰的就是它。
● Decorator装饰角色:一般是一个抽象类,用来实现接口或抽象方法
● ConcreteDecorator是具体类的装饰类,把最原始,最核心,最基本的东西装饰成其他东西 -
装饰者类模式的优点:
- 装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说,Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构件。
- 装饰者模式是继承关系的一个代替方案。我们看装饰类Decorator,不管装饰多少层,返回的对象还是Component,实现的还是is-a的关系。
- 装饰者模式可以动态的扩展一个实现类的功能
-
装饰类模式的缺点:
- 多层的装饰比较复杂
三.结构图
四.设计类图
五.代码实现
Hero(Component抽象构件类)
package com.practice.Domain;
/*
*Component抽象构件类
*@param heroHurt 英雄伤害值
*@parem HeroLife 英雄生命值
*/
public abstract class Hero {
String description = "Unknown Hero";
public String getDescription() {
return description;
}
public abstract double heroHurt();
public abstract double heroLife();
}
HouYi(ConcreteComponent具体构件)
package com.practice.Domain;
public class HouYi extends Hero {
/*
* ConcreteComponent具体构件:ConcreteComponent是最核心,最原始,最基本的接口或抽象类的实现
*/
public HouYi() {
description = "后羿";
}
public double heroHurt() {
return 300;
}
public double heroLife() {
return 3000;
}
}
Decorate类(Decorator装饰角色)
package com.practice.Decorator;
import com.practice.Domain.Hero;
/*
*Decorate类( Decorator装饰角色)
*/
public abstract class Decorator extends Hero{
public abstract String getDescription();
}
FengBao类(铭文:风暴——具体类的装饰类)
package com.practice.Device;
import com.practice.Decorator.Decorator;
import com.practice.Domain.Hero;
/*
* FengBao类(铭文:风暴——具体类的装饰类)
* 增加伤害值
*/
public class FengBao extends Decorator{
Hero hero;
public FengBao(Hero hero) {
this.hero = hero;
}
public String getDescription() {
return "->装备风暴铭文,增加0.5%暴击效果<-
";
}
public double heroHurt() {
return (1+0.05)*hero.heroHurt();
}
public double heroLife() {
return hero.heroLife()+0;
}
}
PoJun类(装备:破军——Decorator装饰角色)
package com.practice.Device;
import com.practice.Decorator.Decorator;
import com.practice.Domain.Hero;
/*
* PoJun类(装饰角色)
* 增加英雄伤害值
*/
public class PoJun extends Decorator{
Hero hero;
public PoJun(Hero hero) {
this.hero = hero;
}
public String getDescription() {
return hero.getDescription() + "->购买装备破军,增加150物理攻击<-
";
}
public double heroHurt() {
return hero.heroHurt() + 150;
}
public double heroLife() {
return hero.heroLife() + 0;
}
}
BaZheZhongZhuang(装备:霸者重装——Decorator装饰角色)
package com.practice.Device;
import com.practice.Decorator.Decorator;
import com.practice.Domain.Hero;
/*
* BaZheZhongZhuang类
* 增加英雄生命值
*/
public class BaZheZhongZhuang extends Decorator
{
Hero hero;
public BaZheZhongZhuang(Hero hero) {
this.hero = hero;
}
public String getDescription() {
return hero.getDescription() + "->购买霸者重装,生命值提升2000<-
";
}
public double heroHurt() {
return hero.heroHurt() + 0;
}
public double heroLife() {
return hero.heroLife() + 2000;
}
}
Test(测试类)
package com.practice.Test;
import com.practice.Device.BaZheZhongZhuang;
import com.practice.Device.FengBao;
import com.practice.Device.PoJun;
import com.practice.Domain.Hero;
import com.practice.Domain.HouYi;
/*
* 测试类
*/
public class Test {
public static void main(String[] args) {
Hero Houyi = new HouYi();
System.out.println(Houyi.getDescription() + "基础伤害:" + Houyi.heroHurt());
System.out.println(Houyi.getDescription() + "基础生命值:" + Houyi.heroLife());
Houyi = new FengBao(Houyi);
Houyi = new PoJun(Houyi);
Houyi = new BaZheZhongZhuang(Houyi);
System.out.println(Houyi.getDescription() + "伤害值" + Houyi.heroHurt());
System.out.println("生命值" + Houyi.heroLife());
}
}