【设计模式】装饰者模式:以造梦西游的例子讲解一下装饰者模式,这也是你的童年吗?

时间:2022-11-21 14:51:08

1 概述

1.1 问题

众所周知,造梦西游3有四个角色,也就是师徒四人,这师徒四人每个人都有自己专属的武器和装备。假定我们以及设计出来了Role(角色类),并通过继承的方式创造出来了师徒四人的角色(这里只写两个)。

【设计模式】装饰者模式:以造梦西游的例子讲解一下装饰者模式,这也是你的童年吗?

那么这时候问题来了,如果给角色增加一个武器,该怎么实现呢》

【设计模式】装饰者模式:以造梦西游的例子讲解一下装饰者模式,这也是你的童年吗?

我想你头脑中第一印象会想到继承

如下,创建两个武器九尺钉耙和金箍棒

【设计模式】装饰者模式:以造梦西游的例子讲解一下装饰者模式,这也是你的童年吗?

【设计模式】装饰者模式:以造梦西游的例子讲解一下装饰者模式,这也是你的童年吗?

这样九尺钉耙和金箍棒就和角色联系起来了,这时候你可以很清晰的发现,如果在增加一个武器,如月牙弓,你就需要分别创建两个子类。如果再增加一个新角色,如沙僧的话,又要增加更多的子类,这实在是太麻烦。就在你疑惑不解,大骂恶心的时候,我们本篇文章的主角装饰者模式闪亮登场了。

1.2 定义

装饰者模式:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。

1.3 结构

装饰者模式有四个角色:

  • 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构建角色(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色:继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构建的功能。
  • 具体装饰角色(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

1.4 类图

【设计模式】装饰者模式:以造梦西游的例子讲解一下装饰者模式,这也是你的童年吗?

2 例子

2.1 代码

Role.java

public abstract class Role {
    /* 攻击力 */
    private float aggressivity;
    /* 描述 */
    private String explain;
    /* 计算攻击力的方法 */
    public abstract float calculate();

    public Role(float aggressivity, String explain) {
        this.aggressivity = aggressivity;
        this.explain = explain;
    }

    public float getAggressivity() {
        return aggressivity;
    }

    public void setAggressivity(float aggressivity) {
        this.aggressivity = aggressivity;
    }

    public String getExplain() {
        return explain;
    }

    public void setExplain(String explain) {
        this.explain = explain;
    }
}

Equipment.java

public abstract class Equipment extends Role{
    /* 角色的变量 */
     Role role;

    public Equipment(float aggressivity, String explain, Role role) {
        super(aggressivity, explain);
        this.role = role;
    }

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }
}

Wukong.java

public class WuKong extends Role{
    public WuKong() {
        super(150, "孙悟空");
    }

    public float calculate() {
        return getAggressivity();
    }
}

Bajie.java

public class BaJie extends Role{
    public BaJie() {
        super(80, "猪八戒");
    }

    public float calculate() {
        return getAggressivity();
    }
}

GoldHoopRod.java

public class GoldHoopRod extends Equipment{
    public GoldHoopRod(Role role) {
        super(90, "金箍棒", role);
    }

    public float calculate() {

        return getAggressivity()+role.calculate();
    }


    public String getExplain() {
        return super.getExplain()+role.getExplain();
    }
}

NineToothRake.java

public class NineToothRake extends Equipment{
    public NineToothRake(Role role) {
        super(60, "九尺钉耙", role);
    }

    public float calculate() {

        return getAggressivity()+role.calculate();
    }


    public String getExplain() {
        return super.getExplain()+role.getExplain();
    }
}


Player.java

package com.you.Demo19;

public class Player {
    public static void main(String[] args) {
        Role role = new WuKong();
        System.out.println("原始的角色:"+role.getExplain()+"  的战斗力  "+role.getAggressivity());
        System.out.println("---------------------------");
        /* 猴哥拿起金箍棒的战斗力 */
        role = new GoldHoopRod(role);
        System.out.println(role.getExplain()+"  "+role.calculate());
        /* 猴哥拿起九尺钉耙+金箍棒的战斗力 */
        role = new NineToothRake(role);
        System.out.println("---------------------------");
        System.out.println(role.getExplain()+" "+role.calculate());
        /* 猪八戒拿起支持钉耙~战斗力 */
        System.out.println("----------------------------");
        Role role1 = new BaJie();
        role1 = new NineToothRake(role1);
        System.out.println(role1.getExplain()+"   "+role1.calculate());


    }
}

2.2 效果图

【设计模式】装饰者模式:以造梦西游的例子讲解一下装饰者模式,这也是你的童年吗?

3 优点及适用场景

3.1 优点

  • 装饰者模式可以带来比继承更具灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果,装饰者模式比继承更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者是动态的附加责任。
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态拓展一个实现类的功能。

3.2 适用场景

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时(主要有两类)
    • 第一类是系统中存在大量独立的拓展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如Final类)
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
  • 当对象的功能要求可以动态添加,也可以再动态地撤销时。

在本例子中,指的就是把装备类删掉,并不影响原有的代码。

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时(主要有两类)
    • 第一类是系统中存在大量独立的拓展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如Final类)
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
  • 当对象的功能要求可以动态添加,也可以再动态地撤销时。

在本例子中,指的就是把装备类删掉,并不影响原有的代码。