GoF之装饰模式遇见王者荣耀、刺激战场

装饰(Decorator Pattern)模式
在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。就增加功能来说,装饰模式比生成子类更为灵活。
使用场景:

  1. 需要扩展一个类的功能,或给一个类添加附加职责。

  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

4.当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

优点:
1.Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。

  1. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

缺点:

  1. 这种比继承更加灵活机动的特性,同时也更加复杂。

  2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。

3.装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

具体实现:
例1:王者荣耀英雄角色安琪拉,学三个技能,1(Q)、2(W)、3(E)的动态实现。

//Component 英雄接口
publicinterface Hero {
//学习技能
void learnSkills();
}
//ConcreteComponent具体英雄安琪拉,这里可以用新的英雄实现类来增加新英雄角色
public class Angela implements Hero {
private String name;
public Angela(Stringname) {
this.name = name;
}
@Override
public void learnSkills() {
System.out.println(name + “学习了以上技能!”);
}
}
//Decorator 技能池 通过增加英雄实现类,可以增加英雄技能池、皮肤池、武器池等待
public abstractSkills implements Hero{
//持有一个英雄对象接口
private Hero hero;
public Skills(Herohero) {
this.hero = hero;
}
@Override
public void learnSkills() {
if(hero != null)
hero.learnSkills();
}
}
//ConreteDecorator技能:Q 通过增加技能实现类即可增加技能种类
public class Skill_Q extends Skills{
private String skillName;
public Skill_Q(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
}
@Override
public voidlearnSkills() {
System.out.println(“学习技能Q:”+skillName);
super.learnSkills();
}
}
//ConreteDecorator 技能:W
public class Skill_W extends Skills{
private String skillName;
public Skill_W(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
}
@Override
public voidlearnSkills() {
System.out.println(“学习技能W:”+ skillName);
super.learnSkills();
}
}
//ConreteDecorator 技能:E
public class Skill_E extends Skills{
private String skillName;
public Skill_E(Hero hero,StringskillName) {
super(hero);
this.skillName =skillName;
}
@Override
public voidlearnSkills() {
System.out.println(“学习技能E:”+skillName);
super.learnSkills();
}
}
//客户端:召唤师
public class Player {
public static void main(String[]args) {
//选择英雄 有多少英雄接口实现类 就有多少种选择
Hero hero = newAngela(“安琪拉”);
Skills skills = new Skills(hero);
//装扮的顺序不限 此为单独学习技能
Skills q = new Skill_Q(skills,“火球术”);
Skillsw = new Skill_W(skills,“混沌火种”);
Skillse = new Skill_E(skills,“制热光辉”);
//学习技能
q.learnSkills();
w.learnSkills();
e.learnSkills();
//一整套技能学习
Skills q = newSkill_Q(skills,“火球术”);
Skills w = newSkill_W(q,“混沌火种”);
Skills e = newSkill_E(w,“制热光辉”);
e.learnSkills();
}
}
例2:《刺激战场》游戏里面装备98K枪械,更换弹夹、倍镜。

Kar 98K有5发子弹;

装上弹匣后有10发子弹;

装上4倍镜后可以进行4倍瞄准;

装上8倍镜后可以进行4倍瞄准、8倍瞄准。

//定义具备射击功能的枪械接口
public interface Gun {
//射击
publicvoid fire();
}
//创建具体的枪械实现类Kar98K,默认5发子弹
public class Kar98K implements Gun {
@Override
publicvoid fire() {
System.out.println(“射击5次”);
}
}
//对枪械的弹夹进行装饰,抽象实现枪械接口
public abstract class AbstractMagazine implements Gun{
//持有枪械对象
private Gun gun;
public AbstractMagazine(Gun gun) {
this.gun = gun;
}
@Override
public void fire() {
gun.fire();
}
}
//枪械弹夹装饰的具体实现类,子弹增加至10发
public class Magazine extends AbstractMagazine {
public Magazine(Gun gun) {
super(gun);
}
@Override
public void fire() {
System.out.println(“射击10次”);
}
}
//客户端
public class Player {
public static void main(String[] args) {
//捡起一把98K
Gun gun = newKar98K();
//射击5次
gun.fire();
//装饰上弹匣
gun = new Magazine(gun);
//射击10次
gun.fire();
}
}
现在我要装上4倍镜,使它具有4倍瞄准功能,这是枪支原本没有的功能。
扩展枪支接口功能:
//对枪械接口的继承,再增加倍镜装饰
public interface Aim4X extends Gun {
public void aim4X();
}
public abstract class AbstractTelescope4X implements Aim4X {
private Gun gun;
public AbstractTelescope4X(Gun gun) {
this.gun = gun;
}
@Override
public void fire() {
gun.fire();
}
}
public class Telescope4X extends AbstractTelescope4X {
public Telescope4X(Gun gun) {
super(gun);
}
@Override
publicvoid aim4X() {
System.out.println(“已进入4倍瞄准模式”);
}
}
//55式4倍镜
public class Telescope4X55 extends AbstractTelescope4X {
public Telescope4X55(Gun gun) {
super(gun);
}
@Override
publicvoid aim4X() {
System.out.println(“4倍超级瞄准已部署”);
}
}

public class Player {
public static void main(String[] args) {
//捡起一把98K
Gun gun = newKar98K();
//装饰上4倍镜
Aim4X aim4X = new Telescope4X(gun);
//4倍瞄准]
aim4X.aim4X();
//射击
aim4X.fire();
//先装饰上弹匣
gun = new Magazine(gun);
//再装饰上4倍镜
aim4X = new Telescope4X(gun);
//4倍瞄准
aim4X.aim4X();
//换上55式4倍镜
aim4X = new Telescope4X55(gun);
//射击!
aim4X.fire();
}
}
现在我要装上8倍镜,它具有4倍瞄准功能,也具有8倍瞄准功能。
扩展接口:
public interface Aim8X extends Aim4X {
public void aim8X();
}
public abstract class AbstractTelescope8X implements Aim8X {
private Gun gun;
public AbstractTelescope8X(Gun gun) {
this.gun = gun;
}
@Override
public void fire() {
gun.fire();
}
}
public class Telescope8X extends AbstractTelescope8X {
public Telescope8X(Gun gun) {
super(gun);
}
@Override
publicvoid aim8X() {
System.out.println(“进入8倍瞄准模式”);
}
@Override
publicvoid aim4X() {
System.out.println(“进入4倍瞄准模式”);
}
}

public class Player {
public static void main(String[] args) {
//先装饰上弹匣
gun = new Magazine(gun);
//再装饰上8倍镜
aim8X = new Telescope8X(gun);
//8倍瞄准
aim8X.aim8X();
//敌人很近,换4倍
aim8X.aim4X();
//射击!
aim8X.fire();
}
}

欢迎关注微信公众号搜索“专注一行代码”哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值