设计模式:装饰者模式

装饰者模式

类型:结构型

动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性。

具体做法就是不断的包装,然后获得总价可以通过递归的形式由内向外获得所有花费之和
可以参考下面这张图

  1. 将LongBlack咖啡先包装进Milk类的对象内,表示加入了牛奶
  2. 然后再包装进Chocalate类的对象内,表示加入了巧克力
  3. 然后又包装进Chocalate类的对象内,表示再次加入了巧克力
    在这里插入图片描述

角色

  1. Component(被装饰对象的基类)
    定义一个对象接口,可以给这些对象动态地添加职责。
  2. ConcreteComponent(具体被装饰对象)
    定义一个对象,可以给这个对象添加一些职责。
  3. Decorator(装饰者抽象类)
    维持一个指向Component实例的引用,并定义一个与Component接口一致的接口。
  4. ConcreteDecorator(具体装饰者)
    具体的装饰对象,给内部持有的具体被装饰对象,增加具体的职责。

UML

在这里插入图片描述

包结构

在这里插入图片描述

component

基类

package 装饰者模式.component;

public abstract class Dish {
    private String description="";
    private int price=0;

    public abstract int getAllCost();

    public abstract String getAllDesc();


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

    public String getDescription() {
        return description;
    }

    public int getPrice() {
        return price;
    }

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

具体子类

package 装饰者模式.component;

public class Fish extends Dish{
    public Fish(){
        super.setDescription("一条鱼");
        super.setPrice(100000);
    }
    @Override
    public int getAllCost() {
        return super.getPrice();
    }

    @Override
    public String getAllDesc() {
        return super.getDescription();
    }
}
--------------------------------------------
package 装饰者模式.component;

public class Soup extends Dish{
    public Soup(){
        super.setDescription("一碗汤");
        super.setPrice(1000);
    }
    @Override
    public int getAllCost() {
        return super.getPrice();
    }

    @Override
    public String getAllDesc() {
        return super.getDescription();
    }
}
--------------------------------------------
package 装饰者模式.component;

public class Tofu extends Dish{
    public Tofu(){
        super.setDescription("一块豆腐");
        super.setPrice(10000);
    }
    @Override
    public int getAllCost() {
        return super.getPrice();
    }

    @Override
    public String getAllDesc() {
        return super.getDescription();
    }
}

装饰者

基类

package 装饰者模式.decorator;

import 装饰者模式.component.Dish;

public class Seasoning extends Dish{
    private Dish dish;
    public Seasoning(Dish dish){
        this.dish=dish;
    }

    @Override
    public int getAllCost() {
        //用递归的方法去获得价格
        //加号前面为该菜之前的花费,加号后面为当前调料的花费
        return dish.getAllCost()+super.getPrice();
    }

    @Override
    public String getAllDesc() {
        //用递归的方法去获得描述
        return dish.getAllDesc()+super.getDescription();
    }
}

具体子类

package 装饰者模式.decorator;

import 装饰者模式.component.Dish;

public class Oil extends Seasoning{
    public Oil(Dish dish) {
        super(dish);
        super.setPrice(100);
        super.setDescription("+油");
    }
}
----------------------------------------
package 装饰者模式.decorator;

import 装饰者模式.component.Dish;

public class Salt extends Seasoning{
    public Salt(Dish dish) {
        super(dish);
        super.setPrice(10);
        super.setDescription("+盐");
    }
}
----------------------------------------
package 装饰者模式.decorator;

import 装饰者模式.component.Dish;

public class Sugar extends Seasoning{

    public Sugar(Dish dish) {
        super(dish);
        super.setPrice(1);
        super.setDescription("+糖");
    }
}

客户端

package 装饰者模式.client;

import 装饰者模式.component.Dish;
import 装饰者模式.component.Fish;
import 装饰者模式.component.Tofu;
import 装饰者模式.decorator.Oil;
import 装饰者模式.decorator.Salt;
import 装饰者模式.decorator.Sugar;

public class Client {
    public static void main(String[] args) {
        //未经处理的鱼
        Dish fish = new Fish();
        System.out.println(fish.getAllDesc());
        System.out.println("花费为"+fish.getAllCost()+'\n');
        //加油
        fish = new Oil(fish);
        System.out.println(fish.getAllDesc());
        System.out.println("花费为"+fish.getAllCost()+'\n');
        //加盐
        fish = new Salt(fish);
        System.out.println(fish.getAllDesc());
        System.out.println("花费为"+fish.getAllCost()+'\n');
        //加糖
        fish = new Sugar(fish);
        System.out.println(fish.getAllDesc());
        System.out.println("花费为"+fish.getAllCost()+'\n');
        //加盐
        fish = new Salt(fish);
        System.out.println(fish.getAllDesc());
        System.out.println("花费为"+fish.getAllCost()+'\n');
        /*-----------------------------------------------------*/
        //未经处理的豆腐
        Dish tofu = new Tofu();
        tofu=new Oil(new Salt(tofu));
        System.out.println(tofu.getAllDesc());
        System.out.println("花费为"+tofu.getAllCost()+'\n');
    }
}

效果

一条鱼
花费为100000

一条鱼+油
花费为100100

一条鱼++盐
花费为100110

一条鱼+++糖
花费为100111

一条鱼++++盐
花费为100121

一块豆腐++油
花费为10110


Process finished with exit code 0

总结

  • 装饰者和被装饰者之间必须是一样的类型,也就是要有共同的超类。
  • 在这里使用继承并不是实现方法的复制,而是实现类型的匹配。因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。
  • 虽然装饰者模式可以为设计注入弹性,但装饰者也常常造成设计中有大量的小对象,如果过度使用会让程序变得很复杂。
    • 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值