装饰者模式

什么是装饰者设计模式

装饰着模式:简单的一句话理解就是,动态的给一个对象添加一些额外的功能,装饰者模式相对于生成子类更加的灵活

装饰者设计模式UML图

可以通俗理解为

装饰者设计模式的组成

  • Component(抽象构件):它是装饰类和具体构件的公共父类;

  • ConcreteComponent(具体构件):具它是抽象构件对象的子类,用来定义具体的构件对象;

  • Decorator(抽象装饰类):进继承抽象构件,用于给具体的构件添加一些新的职责;

  • ConcreteDecoraror(具体装饰类):实现了抽象装饰类,它负责向构件添加新的职责;

奶茶实例演示

业务场景:现我们现在模拟这样一个场景,我们点了一杯奶茶,然后给奶茶中加了冰块,加了珍珠,最后我们还想再给加点红豆,这里加红豆就使用了装饰者。

Component - 奶茶抽象类

 public interface MilkyTea {
 ​
    public void recipe();
 }public interface MilkyTea {
 ​
    public void recipe();
 }
 public class MilkyTeaA implements MilkyTea {
    @Override
    public void recipe() {
        System.out.println("老板来一杯奶茶,加冰块");
    }
 }public class MilkyTeaA implements MilkyTea {
    @Override
    public void recipe() {
        System.out.println("老板来一杯奶茶,加冰块");
    }
 }
 public class Decorator implements MilkyTea {
 ​
    private MilkyTea milkyTea;
 ​
    public void setMilkyTea(MilkyTea milkyTea) {
        this.milkyTea = milkyTea;
    }
 ​
    @Override
    public void recipe() {
        milkyTea.recipe();
    }
 }public class Decorator implements MilkyTea {
 ​
    private MilkyTea milkyTea;
 ​
    public void setMilkyTea(MilkyTea milkyTea) {
        this.milkyTea = milkyTea;
    }
 ​
    @Override
    public void recipe() {
        milkyTea.recipe();
    }
 }
 public class MilkyTeaADecorator extends Decorator {
 ​
    @Override
    public void recipe() {
        super.recipe();
        recipeHD();
    }
 ​
    public void recipeHD() {
        System.out.println("老板再给加点珍珠吧");
    }
 }public class MilkyTeaADecorator extends Decorator {
 ​
    @Override
    public void recipe() {
        super.recipe();
        recipeHD();
    }
 ​
    public void recipeHD() {
        System.out.println("老板再给加点珍珠吧");
    }
 }
 public class MilkyTeaBDecorator extends Decorator {
 ​
    @Override
    public void recipe() {
        super.recipe();
        recipeHD();
    }
 ​
    public void recipeHD() {
        System.out.println("老板你再给加点红豆吧");
    }
 }public class MilkyTeaBDecorator extends Decorator {
 ​
    @Override
    public void recipe() {
        super.recipe();
        recipeHD();
    }
 ​
    public void recipeHD() {
        System.out.println("老板你再给加点红豆吧");
    }
 }
 public class Test {
 ​
    public static void main(String[] args) {
 ​
        MilkyTeaA milkyTea = new MilkyTeaA();
 ​
        MilkyTeaADecorator milkyTeaA = new MilkyTeaADecorator();
        MilkyTeaBDecorator milkyTeaB = new MilkyTeaBDecorator();
 ​
        milkyTeaA.setMilkyTea(milkyTea);
        milkyTeaB.setMilkyTea(milkyTeaA);
 ​
        milkyTeaB.recipe();
    }
 }public class Test {
 ​
    public static void main(String[] args) {
 ​
        MilkyTeaA milkyTea = new MilkyTeaA();
 ​
        MilkyTeaADecorator milkyTeaA = new MilkyTeaADecorator();
        MilkyTeaBDecorator milkyTeaB = new MilkyTeaBDecorator();
 ​
        milkyTeaA.setMilkyTea(milkyTea);
        milkyTeaB.setMilkyTea(milkyTeaA);
 ​
        milkyTeaB.recipe();
    }
 }
 public interface Package {
 ​
     public String title();
 ​
     public List<String> content();
 ​
     public Double price();
 }public interface Package {
 ​
     public String title();
 ​
     public List<String> content();
 ​
     public Double price();
 }
 public class PackageA implements Package {
 ​
     // 使用单例设计模式
     public static class Instance{
         public static List<String> content = new ArrayList<>();
 ​
         public static Double price = 0.0D;
     }
 ​
 ​
     @Override
     public String title() {
         return "套餐A - 典雅黑森林";
     }
 ​
     @Override
     public List<String> content() {
         Instance.content.add("黑森林门板");
         Instance.content.add("黑森林门套");
         Instance.content.add("黑森林子门");
         Instance.content.add("黑森林门锁");
         Instance.content.add("黑森林门窗");
         return Instance.content;
     }
 ​
     @Override
     public Double price() {
         Instance.price += 2506.3;
         return Instance.price;
     }
 }public class PackageA implements Package {
 ​
     // 使用单例设计模式
     public static class Instance{
         public static List<String> content = new ArrayList<>();
 ​
         public static Double price = 0.0D;
     }
 ​
 ​
     @Override
     public String title() {
         return "套餐A - 典雅黑森林";
     }
 ​
     @Override
     public List<String> content() {
         Instance.content.add("黑森林门板");
         Instance.content.add("黑森林门套");
         Instance.content.add("黑森林子门");
         Instance.content.add("黑森林门锁");
         Instance.content.add("黑森林门窗");
         return Instance.content;
     }
 ​
     @Override
     public Double price() {
         Instance.price += 2506.3;
         return Instance.price;
     }
 }

笃志,励前行。

让我们每天积累一小点知识,争取早日成为技术大牛~

可能这个真实项目小例子不能很好的说明装饰者模式的作用(有一点违反开放-关闭原则),可以看在JDK中的应用就可以得出这个模式的用途以及查看第二节的UML图就可以简单的了解装饰者模式的使用方式了。

本小案例充分使用了之前学习的单例设计模式,建造者设计模式装饰者设计模式,达到了可以灵活装配套餐中的内容,由于不是实际项目的数据,所以暂时定了三个参数,分别是 套餐名、套餐内容、套餐价格,然后可以很灵活的装配这三个属性的任何内容。但是还是遇到了代码量过多,逻辑比较混乱的弊端,所以欢迎大佬们在下面提出意见~

思考

结果

public class Test {

    public static void main(String[] args) {
        PackageA packageA = new PackageA();

        //删除黑森林门套,增加红珍珠门套
        Decorator product = new ProductDecorator().setAddTarget("红珍珠门套").setRemoveTarget("黑森林门套").buildObject();
        // 打8折
        Decorator price = new PriceDecorator().setPercent(0.8D).buildObject();
        // 修改套餐名称
        Decorator title = new TitleDecorator().setTargetTitle("套餐A - 红珍珠改款").buildObject();

        product.setPackage(packageA);
        price.setPackage(product);
        title.setPackage(price);

        System.out.println("产品名称" + title.title() + "\r\n" + "产品内容" + title.content() + "\r\n" + "产品价格" + title.price());
    }
}

测试类

public class TitleDecorator extends Decorator {

    private String targetTitle;

    public TitleDecorator() {
    }

    public TitleDecorator(String targetTitle) {
        this.targetTitle = targetTitle;
    }

    @Override
    public String title() {
        return targetTitle;
    }

    public TitleDecorator setTargetTitle(String targetTitle) {
        this.targetTitle = targetTitle;
        return this;
    }
	 // 使用建造者模式
    public TitleDecorator buildObject(){
        return new TitleDecorator(targetTitle);
    }
}

套餐名称装饰子类

public class PriceDecorator extends Decorator {

    private Double percent;

    public PriceDecorator() {
    }

    public PriceDecorator(Double percent) {
        this.percent = percent;
    }

    @Override
    public Double price() {
        return super.price() * percent;
    }

    public PriceDecorator setPercent(Double percent) {
        this.percent = percent;
        return this;
    }
    // 使用建造者模式
    public PriceDecorator buildObject(){
        return new PriceDecorator(percent);
    }
}

价格装饰子类

public class ProductDecorator extends Decorator {

    private String removeTarget;
    private String addTarget;

    public ProductDecorator() {
    }

    public ProductDecorator(String removeTarget, String addTarget) {
        this.removeTarget = removeTarget;
        this.addTarget = addTarget;
    }

    @Override
    public List<String> content() {
        List<String> content = super.content();
        content.remove(removeTarget);
        content.add(addTarget);
        return content;
    }

    public ProductDecorator setRemoveTarget(String removeTarget) {
        this.removeTarget = removeTarget;
        return this;
    }

    public ProductDecorator setAddTarget(String addTarget) {
        this.addTarget = addTarget;
        return this;
    }
    // 使用建造者模式
    public ProductDecorator buildObject(){
        return new ProductDecorator(removeTarget,addTarget);
    }
}

产品装饰子类

public class Decorator implements Package {

    private Package p;

    public void setPackage(Package p) {
        this.p = p;
    }


    @Override
    public String title() {
        return p.title();
    }

    @Override
    public List<String> content() {
        return p.content();
    }

    @Override
    public Double price() {
        return p.price();
    }
}

装饰类

套餐A 具体内容

套餐抽象接口

在北京闼闼木门项目这边,本周有一个需求,就是添加一个套餐活动,每个套餐内包含的木门材料都不同,当然价格也不同,并且还要考虑销售范围,每个套餐的销售范围不同,每个产品的销售范围不同,要同时符合才能进行套餐打包,并且套餐内的产品还有可能降价,这边开会的讨论结果争吵的不可开交,有人提议直接使用Json数据写死,价格也写死,我虽然不负责块项目,但是我感觉这样写比较Low,其实这个需求使用装饰者编码模式可以很好解决,下面我来演示一下如何使用装饰者模式来解决这个需求(非业务代码,只是想法的实现)

真实项目的思考

说起装饰者模式在JDK中的应用,我们在学习Java SE阶段的IO流时就遇到过,不知道大家还记得InputStream不?当我们有特殊需要,我们还可以使用

  • BufferedInputStream

    完成了缓存功能,使读取文件速度大大提升

  • DataInputStream

    把byte转换成Java基本数据类型

  • FileInputStream

    读取文件

等等等(详情见下图),以下这几个类就是对InputStream类的装饰,达到了不同用途的作用。

装饰者模式在JDK中的应用

结果:

测试

 

MilkyTeaADecorator - 装饰类子类

Decorator - 装饰类

ConcreteComponent- 奶茶具体子类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值