我什么时候应该使用复合设计模式?

kev*_*vin 60 design-patterns composite

我不明白何时应该使用复合设计模式. 我将从这种设计模式中获得哪些好处? 我访问了这个网站,但它只告诉我设计模式的结构,而不是使用它的场景.我希望像我这样的程序员开始学习设计模式会有所帮助.

Sis*_*hus 71

复合是一种模式,在您可能需要选择性地将一组对象组合作为"相同"时,它们实际上是不同的时候是有用的.通常,所使用的示例在处理叶子和节点方面相同,但该模式也可以扩展到异构列表.

例如,考虑去看医生.当您去看医生时会发生各种各样的事情,您通常会先看护士或助理,他们会接受您的体温等等.然后医生会进行检查并进行诊断.然后医生可能会做一些治疗,但护士往往会回来完成治疗.在访问期间执行不同的活动.您有重量和温度等观察结果.但是,例如实验室将是一个不同的对象,因为它通常需要一个样本,然后可以将其发送出去并要求在以后记录结果.

所以我们有软件允许记录所有这些,它通常会创建某种类型的层次结构,如:

遭遇:
PreExam
考试
处理

在每个节点下,您将拥有各种条目,如诊断,观察,实验室程序,诊断,注射等.

这一切都很好,你最终得到了一个结构化的,虽然非常复杂的相遇记录.

现在假设你需要生成账单.突然间,你面临着一个非常不同的要求.您的医疗记录需要创建一个非常准确的相遇图片.在计费中,虽然您不关心谁做了什么或以什么顺序执行,但实际上您并不关心除了结算代码之外的活动.您只需要一个可计费活动列表,即代码.

这些信息不仅嵌入在记录中,而且记录也很难遍历,因为它包含大量不同的对象.它在层次结构中也是可变的 - 如果你的头脑中有钉子,他们可能会跳过任何类型的预检,或者检查这个问题并去治疗.如果您进去拆除缝线,可能没有任何预考或考试.每年的身体没有治疗.等等很难枚举这种对象图.

复合模式解决了这一切.您可以为所有对象定义公共接口或基类.我们称之为"CareEntry".CareEntry有一个属性BillingCode.现在你的Encounter看起来是一个简单的容器,里面只有CareEntry对象.您的计费服务现在可以简单地枚举内部的所有内容,而无需担心某些节点(PreExam,Exam)与叶子(体重温度),或者对象所在的节点(PreExam Exam等)或实际类型是什么对象是(实验室,注射等).一切都是CareEntry并统一对待 - 您只需枚举Encounter中的所有CareEntry对象,并收集每个具有非空帐单代码的对象,您就完成了.它是如此简单.

  • 是.许多应用程序必须处理分层数据.Composite允许您以统一的方式处理分层的异构数据,而无需转换对象,评估其类型以及执行条件以查看它们是否包含其他对象. (5认同)
  • 顺便问一下,它经常使用吗? (2认同)

Don*_*oby 30

引用设计模式,

使用复合图案时

  • 您想要表示对象的部分整体层次结构.
  • 您希望客户能够忽略对象组合和单个对象之间的差异.客户端将统一处理复合结构中的所有对象.

一种常见的用法是在书中用作激励示例的一种用法,即图形窗口的显示系统,其可以包含其他窗口和图形元素,例如图像,文本.复合可以在运行时组合,客户端代码可以操作所有元素,而无需考虑它对于常见操作(如绘图)的类型.


bha*_*ran 20

复合模式允许客户统一处理单个对象以及(单个对象)组合.
例如,双击文件夹时应该打开文件夹.在文件的两倍,它应该在相应的程序中打开.
操作相同,但基于是单个对象还是组合来表现

单个对象和复合对象的通用接口

interface Data{
    public void doubleClick();
}
Run Code Online (Sandbox Code Playgroud)

单个对象实现

class File implements Data {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public void doubleClick() {
        System.out.println(this.getName()+" file is Opened in a Program ");
    }
}
Run Code Online (Sandbox Code Playgroud)

综合实施

class Folder implements Data {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    private List<Data> folder = new ArrayList<Data>();

    @Override
    public void doubleClick() {
        System.out.println(this.getName() + " folder is Opened");
        for(Data data : folder) {
            data.doubleClick();
        }
    }

    public void add(Data data) {
        folder.add(data);
    }

    public void remove(Data data) {
        folder.remove(data);
    }
}
Run Code Online (Sandbox Code Playgroud)

客户计划

public class CompositePattern {

    public static void main(String[] args) {

        Folder f1 = new Folder();f1.setName("Folder 1");
        Folder f2 = new Folder();f2.setName("Folder 2");
        Folder f3 = new Folder();f3.setName("Folder 3");

        File file1 = new File();file1.setName("File 1");
        File file2 = new File();file2.setName("File 2");
        File file3 = new File();file3.setName("File 3");
        File file4 = new File();file4.setName("File 4");

        f1.add(file1);
        f2.add(file2);

        f3.add(f2);
        f3.add(file3);
        f3.add(file4);

        f1.doubleClick();f2.doubleClick();f3.doubleClick();

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 我不明白,为什么文件夹类有一个循环并双击所有项目。这意味着如果我单击一个文件夹,它将打开其中的每个文件。 (5认同)

Zor*_*vat 6

我经常使用Composite设计模式来隐藏集合.在许多情况下,当有许多元素并且其中只有一个元素时,我们以完全相同的方式处理集合.

这就是问题所在,因为包含集合的类然后与foreach循环一起群集,这些循环基本上做同样的事情 - 遍历所有元素并应用一些聚合函数.

为了解决这个问题,我介绍了一个由单个元素实现的接口以及隐藏这些元素集合的类.然后,复合类的目的是包含以前在客户端类中的所有聚合函数.

您可以在本文中找到一些有用的示例:使用集合

这里常见的是,Composite不一定代表整体关系.可以引入复合元素只是为了将循环移出客户端.

这里是一个应用Composite模式隐藏复合元素后面部分的一本书的例子:Composite Design Pattern


小智 5

最近研究并尝试使用它,我认识到一个关于复合材料的重要概念。

复合物隐藏了集合中涉及的复杂性,即循环遍历它们,对其进行分类,过滤某些内容等,并允许您将其视为单个生物。

假设您在一个狗窝有一只狗,而在另一个狗窝有许多狗。您想喂养它们并对其进行疫苗接种,但是如果它们在一个小时内进食就不能喂养它们,或者如果它们在最近五个小时内已经接种过疫苗,则不能喂养它们,或者如果它们呕吐了则对其进行疫苗接种等。

更重要的是,有一个包装顺序规则,即品种A的狗要先于品种B进食,除非品种C的狗在周围并且吠叫到他的肺部。

这将很快达到您根本不需要关心任何东西,而只是打电话给助手并告诉他喂“所有狗”的程度。或者更好的是,三个助手来跟踪喂养,疫苗接种和呕吐,吠叫和包装以及所有其他令人敬畏的东西。

通过召集助手,您可以使用“合成”模式。您只需去“喂食”每个狗窝,无论是一只狗还是十只狗。您只想让装满狗的狗窝自己整理一下,弄清楚它们的觅食方式,因为收银员手中的东西太多了。

因此,对您来说,狗是IDog,是Feed(),Bark(),Vomit()和GetVaccine()的狗。狗窝也是狗,您将其称为kennel.Feed()。大功告成 犬舍犬舍必须弄清楚现在内部应该做什么。它可能有一个计时机制来跟踪每只狗的喂养时间和其他身体功能时间。它全部被整齐地封装。