经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
java设计模式-组合模式详解
来源:jb51  时间:2021/7/19 15:33:14  对本文有异议

组合模式

组合模式(Composite Pattern)又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

  • 主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
  • 如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。
  • 何时使用:

1.您想表示对象的部分-整体层次结构(树形结构)。

2.您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

  • 使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。
优点 缺点
高层模块调用简单,节点自由增加。 叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

在这里插入图片描述

文件夹-文件的树形结构一定不陌生,文件看作叶子结点(单个对象),文件夹看作中间结点(组合对象)。

组合模式使得用户对单个对象和组合对象的访问具有一致性,即让用户以一致的方式处理个别对象以及组合对象。避免在使用过程中区分开来,造成麻烦。

在这里插入图片描述

  • Component :组合中的对象声明接口,用于访问和管理Component子部件。
  • Leaf:单个/叶子对象,叶子结点没有子结点。
  • Composite:组合/容器对象,存储子部件和枝节点行为,实现与子部件有关操作,如增加(add)和删除(remove)等,list实现容器,容纳Component对象。

Demo

先来看看一般的写法:

在这里插入图片描述

当用户只满足一种折扣方案时,这种方法还能应对。

但精打细算的我们往往是同时满足多种折扣方案,这时就可以用组合模式,把这些单个折扣方案组合容纳起来,然后定义解决折扣冲突策略。实现单个对象和组合对象的统一,让调用者使用时不必在区分。

在这里插入图片描述

把组合对象CompositeDiscount定义成抽象类,SingleMinStrategy和MultipleStrategy继承它,表示解决冲突的策略,分别是取最小折扣和取折上折。

一般解决折扣冲突都是折上折,但商家往往更精明,推出互斥券之类的,即取最小折扣。也可以自定义其他折扣冲突策略。

涉及了点工厂模式和策略模式,DiscountFactory就是实例化Order类的属性DiscountStrategy的工厂,各种折扣策略实现同一接口。

代码:

  1. public interface DiscountStrategy {
  2. public double getTotal(double price);
  3. }
  4. public class VIPDiscount implements DiscountStrategy {
  5. //95折
  6. @Override
  7. public double getTotal(double price) {
  8. return 0.95*price;
  9. }
  10. }
  11. public class ActivityDiscount implements DiscountStrategy{
  12. //9折
  13. @Override
  14. public double getTotal(double price) {
  15. return 0.9*price;
  16. }
  17. }
  18. public class StoreDiscount implements DiscountStrategy{
  19. //满500超出部分打6折
  20. @Override
  21. public double getTotal(double price) {
  22. return 500+0.6*(price-500);
  23. }
  24. }
  1. public abstract class CompositeDiscount implements DiscountStrategy {
  2. protected List<DiscountStrategy> strategies =new ArrayList(); //容器
  3. public void add(DiscountStrategy discountStrategy){ //添加叶子结点
  4. strategies.add(discountStrategy);
  5. }
  6. @Override
  7. public double getTotal(double price) {
  8. return price;
  9. }
  10. }
  11. //多种折扣选最低折扣
  12. public class SingleMinStrategy extends CompositeDiscount {
  13. @Override
  14. public double getTotal(double price) {
  15. double rtn=price;
  16. for (DiscountStrategy s: strategies) {
  17. rtn=Math.min(rtn,s.getTotal(price));
  18. }
  19. return rtn;
  20. }
  21. }
  22. //多种折扣用折上折
  23. public class MultipleStrategy extends CompositeDiscount {
  24. @Override
  25. public double getTotal(double price) {
  26. double rtn = price;
  27. for (DiscountStrategy s : strategies) {
  28. rtn = s.getTotal(rtn);
  29. }
  30. return rtn;
  31. }
  32. }
  1. public class DiscountFactory {
  2. public DiscountStrategy create(String type){ //工厂来创建相应策略
  3. //单一折扣策略
  4. if("ynn".equals(type))return new VIPDiscount();
  5. else if("nyn".equals(type))return new StoreDiscount();
  6. else if("nny".equals(type))return new ActivityDiscount();
  7. else{ //多种折扣策略
  8. CompositeDiscount compositeDiscount;
  9. System.out.println("请选择冲突解决方案:1.折上折 2.最低折");
  10. Scanner scanner=new Scanner(System.in);
  11. int type2=scanner.nextInt();
  12. if(type2==1){
  13. compositeDiscount=new MultipleStrategy();
  14. }
  15. else{
  16. compositeDiscount=new SingleMinStrategy();
  17. }
  18. if(type.charAt(1)=='y')compositeDiscount.add(new StoreDiscount());
  19. if(type.charAt(0)=='y')compositeDiscount.add(new VIPDiscount());
  20. if(type.charAt(2)=='y')compositeDiscount.add(new ActivityDiscount());
  21. return compositeDiscount;
  22. }
  23. }
  24. }
  1. public class Order {
  2. public double price;
  3. private String type;
  4. public DiscountStrategy discountStrategy;
  5. public Order(double price) {
  6. this.price=price;
  7. }
  8. public void display(){
  9. System.out.println("总价:"+price);
  10. System.out.println("是否是VIP?y/n");
  11. Scanner scanner=new Scanner(System.in);
  12. type=scanner.next();
  13. System.out.println("是否超过500?y/n");
  14. String tmp;
  15. tmp=scanner.next();
  16. type+=tmp;
  17. System.out.println("是否满足活动价?y/n");
  18. tmp=scanner.next();
  19. type+=tmp;
  20. DiscountFactory discountFactory=new DiscountFactory();
  21. double discountPrice=discountFactory.create(type).getTotal(price);
  22. System.out.println("优惠:"+(price-discountPrice));
  23. System.out.println("应付:"+discountPrice);
  24. }
  25. }
  26. public class Client {
  27. public static void main(String[] args) {
  28. Order order=new Order(620);
  29. order.display();
  30. }
  31. }

运行结果:

在这里插入图片描述

在这里插入图片描述

这样一来,无论是单一折扣还是多种折扣,客户端使用时都是一个用法,不必区分和操心。

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注w3xue的更多内容!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号