设计模式之装饰器模式

目录

1、什么是装饰器模式

2、装饰器模式结构

3、具体实现

3.1 案例

3.2 代码实现

4、使用场景


1、什么是装饰器模式

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

2、装饰器模式结构

装饰(Decorator)模式中的角色:

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

3、具体实现

3.1 案例

我们先来看以下这个例子:平时我们都肯定吃过快餐,快餐肯定包含了炒饭、炒面等等,有时候“生活富裕”的时候,我们还会加个蛋再来根肠。

那么,如果我们此时想用代码的方式来实现,那肯定最容易想到以下方法:

①定义快餐类。

②定义炒饭类、炒面类来继承快餐类。

③定义蛋炒饭、蛋炒面、火腿肠炒饭、火腿肠炒面、火腿肠蛋炒饭、火腿肠蛋炒面。

显然,这种方式很容易想,不难理解,但是大家也很容易发现一个很严重的问题:“类爆炸”。即我们仅仅是举了炒饭、炒面,配料能加蛋和火腿的例子,就需要上面这么多类。可是正常的快餐店,还有炒河粉、饺子.......配料还有培根、鸡腿、鸭腿......

所以上述这种方式虽然能够实现,但是我们极力反对使用这种方式!不仅难用,而且违反了我们软件设计原则中的“合成复用原则”。因此,这个时候我们就需要使用“装饰者模式”来解决我们遇到的问题了。

3.2 代码实现

以下代码实现依据上述例子来进行实现。(代码有点长,但是很简单的逻辑,大家细心看)

快餐类(抽象构件角色):

public abstract class FastFood { //快餐类
    private String description;//描述
    private int price;//价格
    public abstract int cost(); //返回需要多少钱
    public abstract String Description();//返回当前快餐描述
    public FastFood(String description,int price){
        this.description=description;
        this.price=price;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

炒面类(具体构建角色):

public class FriedNoodle extends FastFood{ //炒面类
    public FriedNoodle(String description, int price) {
        super(description, price);
    }
    @Override
    public int cost() {
        return getPrice();
    }

    @Override
    public String Description() {
        return getDescription();
    }
}

炒饭类(具体构建角色):

public class FriedRice extends FastFood{//炒饭类
    public FriedRice(String description, int price) {
        super(description, price);
    }
    @Override
    public int cost() {
        return getPrice();
    }

    @Override
    public String Description() {
        return getDescription();
    }
}

配料类(抽象装饰角色):

public class SideDish extends FastFood{ //配菜类
    private FastFood fastFood;
    public SideDish(FastFood fastFood,String description, int price) {
        super(description, price);
        this.fastFood=fastFood;
    }
    @Override
    public int cost() {
        //价格应该是加配料前的食物价格+配料价格
        return fastFood.cost()+getPrice();
    }

    @Override
    public String Description() {
        return fastFood.Description()+getDescription();
    }

}

蛋类(具体装饰角色):

public class Egg extends SideDish {
    public Egg(FastFood fastFood, String description, int price) {
        super(fastFood, description, price);
    }
}

火腿肠类(具体装饰角色):

public class Ham extends SideDish {
    public Ham(FastFood fastFood, String description, int price) {
        super(fastFood, description, price);
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        FastFood friedRice = new FriedRice("炒饭", 10);//一开始点了一碗炒饭
        FastFood egg = new Egg(friedRice, "加蛋", 1);//加个蛋
        System.out.println("价格为:"+egg.cost());
        System.out.println("描述为:"+egg.Description());
        System.out.println("--------分界线--------");
        Ham ham = new Ham(egg, "加肠", 2);//加个肠
        System.out.println("价格为:"+ham.cost());
        System.out.println("描述为:"+ham.Description());
    }
}

运行结果:

设计模式之装饰器模式_第1张图片

可见,我们通过上述代码,完成了我们的案例,当然如果此时我们配菜多了一个“培根类”,那也仅需再创建一个“培根类”继承“配菜类”即可。

希望大家能耐心看完上述案例和代码,充分理解装饰器模式的好处。

4、使用场景

①当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:

  • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
  • 第二类是因为类定义不能继承(如final类)

②在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
③当对象的功能要求可以动态地添加,也可以再动态地撤销时。

你可能感兴趣的:(设计模式,设计模式,java,装饰器模式)