了解23种设计模式之组合模式

本文深入探讨了组合模式,一种构造型设计模式,用于构造树形对象结构,使客户端能够一致地处理单个对象和组合对象。文章详细解析了组合模式的结构、角色职责、优缺点,以及透明式和安全式两种实现方式,并提供了具体代码实例。

一,什么是组合模式

 Composite 模式 也叫组合模式,是构造型的设计模式之一,通过递归手段来构造树形的对象结构,并可以通过一个对象来访问整个对象树

二,组合模式的结构

组合模式的角色和职责

Component : (树形结构的节点抽象)   

  • 为所有的对象定义统一的接口,(公共属性,行为等的定义)
  • 提供管理子节点对象的接口方法
  • (选择)提供管理父节点对象的接口方法

Leaf : (树形结构的叶节点)

Composite: (树形结构的枝节点) 

优点:

  1. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
  2. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;

缺点:

  1. 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
  2. 不容易限制容器中的构件;
  3. 不容易用继承的方法来增加构件的新功能;

组合模式分为透明式的组合模式和安全式的组合模式。

 

四:透明方式代码实现:

透明方式:在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。

Component

public interface IFile {

    /**
     * @Description: 显示文件夹的名称
     * @param:
     * @return: void
     **/
    public void display();

    /**
     * @Description: 添加
     * @param: []
     * @return: boolean
     **/
    public boolean add(IFile iFile);

    /**
     * @Description: 删除
     * @param: []
     * @return: boolean
     **/
    public boolean remove(IFile iFile);

    /**
     * @Description: 获得子节点
     * @param: []
     * @return: java.util.List<com.enjoy.cap26.IFile>
     **/
    public List<IFile> getChildren();
 }

Leaf

/**
 * @ClassName Files
 * @Description TODO
 * @Version 1.0
 **/
public class Files implements IFile{

    private String name;

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

    @Override
    public void display() {
        System.out.println(name);
    }

    @Override
    public boolean add(IFile iFile) {
        return false;
    }

    @Override
    public boolean remove(IFile iFile) {
        return false;
    }

    @Override
    public List<IFile> getChildren() {
        return null;
    }
}

 Composite

/**
 * @ClassName Folder
 * @Description TODO
 * @Version 1.0
 **/
public class Folder implements IFile{

    private String name;
    private List<IFile> children;

    public Folder(String name) {
        this.name = name;
        children = new ArrayList<IFile>();
    }

    @Override
    public void display() {
        System.out.println(name);
    }

    @Override
    public boolean add(IFile iFile) {

        return children.add(iFile);
    }

    @Override
    public boolean remove(IFile iFile) {

        return  children.remove(iFile);
    }

    @Override
    public List<IFile> getChildren() {
        return children;
    }
}

测试:

/**
 * @ClassName test
 * @Description TODO
 * @Version 1.0
 **/
public class Test {

    public static void main(String[] args) {
          //父节点
          Folder folder = new Folder("D:");

          //子节点 目录
          Folder javaFoder = new Folder("java");

          //子节点 helloworld.txt
          Files  files = new Files("helloworld.txt");

          folder.add(javaFoder);
          folder.add(files);

          Folder sprFoder = new Folder("spring");
          Files files2 = new Files("springAop-api");
          javaFoder.add(sprFoder);
          javaFoder.add(files2);

          //子节点 目录
          Folder stuFoder = new Folder("学习");
          Files files1 = new Files("String.txt");

          folder.add(stuFoder);
          folder.add(files1);


          displayTree(folder,0);

    }

    /**
     * 使用递归
     * @param iFile
     * @param deep
     */
    public static  void  displayTree(IFile iFile,int deep){
        for (int i = 0; i < deep;i++){
            System.out.print("--");
        }
        //显示自身名称
        iFile.display();

        List<IFile>  children = iFile.getChildren();

        for (IFile file : children) {
            if( file instanceof Files){
                for (int i = 0; i <= deep;i++){
                    System.out.print("---");
                }
                file.display();
            }else{
                displayTree(file,deep+1);
            }
        }

    }

}

五,安全方式

安全方式:在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。

 Component 

/**
 * @ClassName Articles
 * @Description 抽象构建
 * @Version 1.0
 **/
public interface Articles {

    /**
     * @Description: 计算
     * @param: []
     * @return: float
     * @Author: wuchao
     * @Date: 2020/6/26 20:31
     **/
    public float calculation();


    /**
     * @Description: 显示
     * @param: []
     * @return: void
     * @Author: wuchao
     * @Date: 2020/6/26 20:32
     **/
    public  void show();
}

leaf: 

/**
 * @ClassName Goods
 * @Description 树叶构件
 * @Version 1.0
 **/
public class Goods implements  Articles{

    private String name;

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

    /**
     * 单价
     */
    private float unitPrice;


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

    @Override
    public float calculation() {
        return quantity*unitPrice;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public float getUnitPrice() {
        return unitPrice;
    }

    public void setUnitPrice(float unitPrice) {
        this.unitPrice = unitPrice;
    }
}

 

Composite 

/**
 * @ClassName Bags
 * @Description TODO
 * @Version 1.0
 **/
public class Bags implements Articles{

    private String name;
    private List<Articles> list;


    public Bags(String name) {
        this.name = name;
        list = new ArrayList<Articles>();
    }

    @Override
    public float calculation() {
        float s=0;
        for(Object obj:list)
        {
            s+=((Articles)obj).calculation();
        }
        return s;
    }

    @Override
    public void show() {
        for(Object obj:list) {
            ((Articles)obj).show();
        }
    }


    /**
     * 新增对象
     * @param c
     */
    public void add(Articles c) {
        list.add(c);
    }

    /**
     * 删除对象
     * @param c
     */
    public void remove(Articles c) {
        list.remove(c);
    }

    /**
     * 获得list
     * @return
     */
    public List<Articles> getChild(){
        return list;
    }
}

 

 

测试:

public class Test {

    public static void main(String[] args) {
        float s=0;
        Bags BigBag,mediumBag,smallRedBag,smallWhiteBag;
        Goods sp;
        BigBag=new Bags("大袋子");
        mediumBag=new Bags("中袋子");
        smallRedBag=new Bags("红色小袋子");
        smallWhiteBag=new Bags("白色小袋子");
        sp=new Goods("婺源特产",2,7.9f);
        smallRedBag.add(sp);
        sp=new Goods("婺源地图",1,9.9f);
        smallRedBag.add(sp);
        sp=new Goods("韶关香菇",2,68);
        smallWhiteBag.add(sp);
        sp=new Goods("韶关红茶",3,180);
        smallWhiteBag.add(sp);
        sp=new Goods("景德镇瓷器",1,380);
        mediumBag.add(sp);
        mediumBag.add(smallRedBag);
        sp=new Goods("李宁牌运动鞋",1,198);
        BigBag.add(sp);
        BigBag.add(smallWhiteBag);
        BigBag.add(mediumBag);
        System.out.println("您选购的商品有:");
        BigBag.show();
        s=BigBag.calculation();
        System.out.println("要支付的总价是:"+s+"元");
    }
}

  

六,组合模式的应用场景

  1. 在需要表示一个对象整体与部分的层次结构的场合。
  2. 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可乐cc呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值