likes
comments
collection
share

【Java设计模式】结构型设计模式-组合模式(十二)

作者站长头像
站长
· 阅读数 5

组合模式

  • 组合模式的也叫做整体-部分模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性。

进一步阐述:

  • 组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点。其实就是我们常说的“树型结构”。

组合模式包含四种角色:

  • Component(抽象构件角色):它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
  • Leaf(树叶构件角色):是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
  • Composite(树枝构件角色 / 中间构件角色):是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

案例:实现当用户在商店购物后,显示其所选商品信息,并计算所选商品总价的功能。

UML类图:

【Java设计模式】结构型设计模式-组合模式(十二)

客户端Client类:

/**
 * 使用组合模式的客户端
 */
public class Client {

    public static void main(String[] args) {
        Bags bigBag = new Bags("大商品袋");
        Bags mediumBag = new Bags("中商品袋");
        Bags smallBag = new Bags("小商品袋");

        Goods sneakers = new Goods("运动鞋", 1, 1198);
        Goods snacks = new Goods("零食", 5, 5);
        Goods vegetables = new Goods("蔬菜", 5, 1.5);

        //中商品袋中放入运动鞋
        mediumBag.add(sneakers);
        //小商品袋中放入零食和蔬菜
        smallBag.add(snacks);
        smallBag.add(vegetables);
        //把中商品袋和小商品袋一起放入大商品袋组合起来
        bigBag.add(mediumBag);
        bigBag.add(smallBag);
        //打印所有的商品信息
        bigBag.show();
        double total = bigBag.calculation();
        System.out.println("要支付的总价是:" + total);
    }
}

商店物品Articles接口:

/**
 * 商店物品(抽象构件)
 */
public interface Articles {

    /**
     * 计算方法
     */
    double calculation();

    /**
     * 展示信息
     */
    void show();
}

袋子Bags类:

/**
 * 袋子类(树枝构件)
 */
public class Bags implements Articles {

    /**
     * 袋子名称
     */
    private String name;

    /**
     * 持有商品的集合
     */
    private List<Articles> bags = new ArrayList<>();

    public Bags(String name) {
        this.name = name;
    }

    /**
     * 添加商品
     */
    public void add(Articles articles) {
        bags.add(articles);
    }

    /**
     * 删除商品
     */
    public void remove(Articles articles) {
        bags.remove(articles);
    }

    /**
     * 获取某一个商品
     */
    public Articles getChild(int i) {
        return bags.get(i);
    }

    /**
     * 计算所有价格
     */
    public double calculation() {
        BigDecimal total = new BigDecimal("0");
        for (Articles bag : bags) {
            total = total.add(BigDecimal.valueOf(bag.calculation()));
        }
        return total.doubleValue();
    }

    /**
     * 打印所有商品信息
     */
    public void show() {
        for (Articles bag : bags) {
            bag.show();
        }
    }
}

商品Goods类:

/**
 * 商品类(树叶构件)
 */
public class Goods implements Articles {

    /**
     * 商品名称
     */
    private String name;

    /**
     * 商品数量
     */
    private int quantity;

    /**
     * 商品单价
     */
    private double unitPrice;

    public Goods(String name, int quantity, double unitPrice) {
        this.name = name;
        this.quantity = quantity;
        this.unitPrice = unitPrice;
    }

    @Override
    public double calculation() {
        return BigDecimal.valueOf(unitPrice)
                .multiply(BigDecimal.valueOf(quantity)).doubleValue();
    }

    @Override
    public void show() {
        System.out.println(name + "(数量:" + quantity + ",单价:" + unitPrice + "元)");
    }
}

总结:

  • 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码。
  • 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”。
  • 设计较复杂,客户端需要花更多时间理清类之间的层次关系。不容易限制容器中的构件。不容易用继承的方法来增加构件的新功能。

典型运用场景举例:

  • 在需要表示一个对象整体与部分的层次结构的场合。例如:文件目录显示,多及目录呈现等。
  • 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合,比如树形结构中的二叉树。
转载自:https://juejin.cn/post/7356208563101040691
评论
请登录