Java设计模式之装饰模式

装饰模式是设计模式中用得比较频繁的模式了,他是一种不需要改变原始类代码实现功能拓展的一种成熟模式。

那他用在什么场景呢,项目中我们常常遇到这样一种情况,比如某个类的执行某个方法返回了类中的一个变量值,现在有个需求就是变量值我们需要随时改,你首先想到的是修改里面的参数,那如果这个参数是private类型呢,你想那也行啊,我设置一个set方法,那如果这个类没有set方法呢,外界不应许修改或者他本身不是变量是常量怎么办?那你可能会想到另外一个办法,我可以通过反射来修改对象中的属性啊,没错,是可以!但是反射的一个很大缺点就是慢,不适用于过多使用,从系统的健壮性考虑,这个方案不好,那么我们这个时候用装饰模式就能生效了。

实战场景:相信大家都玩过dota、lol这样的游戏,喜欢玩DPS的英雄都希望攻击越高越好,通过打钱然后买装备,英雄有一个初始攻击力(50),假如我通过带装备增加了攻击力,那我们实现起来总不能每带一件装备就修改对象的参数一次吧,而且直接修改角色的属性势必会增加程序的耦合性。那么用装饰模式如何做到呢。不多说 先看类图:


装饰模式里有四种角色,

1.抽象组件:抽象类,定义了一个装饰类需要被装饰的方法,就是上面的角色类,我们这里可以看做是带装备的英雄。

2.具体组件:抽象组件的子类,即被装饰着。对于的就是我们类图的英雄,你可以看做是一个裸装的英雄

3.装饰类:也是抽象类的一个子类,但“”装饰类"也包含抽象组件声明的变量,以保存“”被装饰着"的引用。

4.具体装饰类:听名字都知道是“”装饰者“,就是圣剑、金箍棒这样的武器装备

刚看代码可能还不能理解透彻,下面用代码来加以说明:

抽象组件:

/**
 *  desc  抽象组件 扮演英雄的角色(带装备的)
 */
public interface Role {
    public int attact();
}

具体组件:

/**
 *  desc  具体组件,英雄类(初始属性,不带装备的)
 */
public class Hero implements Role{
    private final int DPS = 50;

    @Override
    public int attact() {
        return DPS;
    }
}

装饰类:

/**
 *  装饰类(抽象的)
 */
public abstract class Equipment implements Role{
    protected Role role;
    public Equipment(){
    }

    public  Equipment(Role role){
        this.role = role;
    }
}
具体三个装饰类:

/**
 *  desc  阔剑装饰类(攻击力加15)
 */
public class Glaive extends Equipment{
    private final int DPS = 15;
    public Glaive(Role role){
        super(role);
    }
    @Override
    public int attact() {
        return role.attact() + DPS;
    }
}
/**
 *  desc  金箍棒装饰类(攻击力加150)
 */
public class GoldenCudgel extends Equipment{
    private final int DPS = 150;
    public GoldenCudgel(Role role){
        super(role);
    }
    @Override
    public int attact() {
        return role.attact() + DPS;
    }

/**
 *  desc  圣剑装饰类(攻击力加300)
 */
public class Excalibur extends Equipment{
    private final int DPS = 300;
    public Excalibur(Role role){
        super(role);
    }
    @Override
    public int attact() {
        return role.attact() + DPS;
    }
}

下面是测试类:

public class Main {
    public void showDPS(Role role){
        System.out.println("孙悟空的此时的输出是"+role.attact());
    }
    public static void main(String args[]){
        Main main = new Main();
        Role role = new Hero(); //实例化这个英雄
        main.showDPS(role); //打印出50的攻击力

        Role role1 = new Glaive(role); //给裸装英雄添加一个阔剑
        main.showDPS(role1);  //打印出65的攻击力

        Role role2 = new GoldenCudgel(role1); //给有阔剑的英雄添加一个金箍棒
        main.showDPS(role2);  //打印出215的攻击力

        Role role3= new Excalibur(role1); //给有阔剑的英雄添加一个圣剑
        main.showDPS(role3);  //打印出365的攻击力
    }
}
打印结果:

怎么样,是不是很简单,装饰模式在实际当中运用的挺广泛的,装饰模式满足“开闭原则”,不必修改具体组件就可以增加新的针对该组件的具体装饰。被装饰着和装饰着是送耦合的关系。

是靠一下,如果我有一个需求,除了随时添加装备,那我还要随时脱掉装备怎么办呢,很简单!从面向对象的思维来想,装备肯定不会自己把自己脱掉,肯定是角色(Role)啦!在Role这个抽象组件中再添加一个卸装备的动作,然后每个具体装饰类实现卸掉的逻辑不就可以了吗?

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值