1、什么是组合模式?
有时候,您觉得需要在代码中使用树数据结构。树的数据结构有许多变化,但有时需要同时处理树的分支和叶子的树。组合模式允许您将对象组合到树结构中,以表示部分-整体层次结构,这意味着您可以创建由不同部分组成的对象树,但可以将其视为一个整体。组合模式允许我们以树的形式构建对象的结构,树既包含对象的组合,也包含作为节点的单个对象。
2、场景分析
复合模式可以在任何具有系统或子系统层次结构的地方实现,并且希望统一地处理单个对象和对象的组合。让我们来看一个简单的例子,其中我们使用组合模式在Java中实现html表示。html本质上是层次结构的,它从<html>标记开始,该标记是父标记或根标记,它包含其他标记,这些标记可以是父标记或子标记。Java中的复合模式可以使用组件类作为抽象类或接口来实现。在本例中,我们将使用一个抽象类,它包含复合类和叶子类中使用的所有重要方法。
import java.util.List;
public abstract class HtmlTag {
public abstract String getTagName();
public abstract void setStartTag(String tag);
public abstract void setEndTag(String tag);
public void setTagBody(String tagBody) {
throw new UnsupportedOperationException("Current operation is not support for this object");
}
public void addChildTag(HtmlTag htmlTag) {
throw new UnsupportedOperationException("Current operation is not support for this object");
s
public void removeChildTag(HtmlTag htmlTag) n
throw new UnsupportedOperationException("Current operation is not support for this object");
}
public List<HtmlTag> getChildren() {
throw new UnsupportedOperationException("Current operation is not support for this object");
}
public abstract void generateHtml();
}
HtmlTag类是一个组件类(Component),它定义了组合(Composite)和叶子类(Leaf)使用的所有方法。有一些方法在这两个扩展类中应该是通用的。因此,这些方法在上面的类中保持抽象,以便在子类中实现它们。
import java.util.ArrayList;
import java.util.List;
public class HtmlParentElement extends HtmlTag {
private String tagName;
private String startTag;
private String endTag;
private List<HtmlTag> childrenTag;
public HtmlParentElement(String tagName) {
this.tagName = tagName;
this.startTag = "";
this.endTag = "";
this.childrenTag = new ArrayList<>();
}
@Override
public String getTagName() {
return tagName;
}
@Override
public void setStartTag(String tag) {
this.startTag = tag;
}
@Override
public void setEndTag(String tag) {
this.endTag = tag;
}
@Override
public void addChildTag(HtmlTag htmlTag) {
childrenTag.add(htmlTag);
}
@Override
public void removeChildTag(HtmlTag htmlTag){
childrenTag.remove(htmlTag);
}
@Override
public List<HtmlTag> getChildren() {
return childrenTag;
}
@Override
public void generateHtml() {
System.out.println(startTag);
for (HtmlTag tag : childrenTag) {
tag.generateHtml();
}
System.out.println(endTag);
}
}
HtmlParentElement类是实现addChildTag、removeChild等方法的复合类标签,getChildren它必须由类实现,以成为结构的组合。这里的操作方法是generateHtml,它打印当前类的标记,并遍历其子类并调用它们的generateHtml方法。
public class HtmlElement extends HtmlTag {
private String tagName;
private String startTag;
private String endTag;
private String tagBody;
public HtmlElement(String tagName) {
this.tagName = tagName;
this.tagBody = "";
this.startTag = "";
this.endTag = "";
}
@Override
public String getTagName() {
return tagName;
}
@Override
public void setStartTag(String tag) {
this.startTag = tag;
}
@Override
public void setEndTag(String tag) {
this.endTag = tag;
}
@Override
public void setTagBody(String tagBody) {
this.tagBody = tagBody;
}
@Override
public void generateHtml() {
System.out.println(startTag + "" + tagBody + "" + endTag);
}
}
HtmlElement是leaf类,它的主要工作是实现操作方法,在本例中是generateHtml方法。它打印子元素的开始标记、可选的tagBody(如果有的话)和结束标记。让我们测试这个例子。
public class TestCompositePattern {
public static void main(String[] args) {
HtmlTag parentTag = new HtmlParentElement("<html>");
parentTag.setStartTag("<html>");
parentTag.setEndTag("</html>");
HtmlTag p1 = new HtmlParentElement("<body>");
p1.setStartTag("<body>");
p1.setEndTag("</body>");
parentTag.addChildTag(p1);
HtmlTag child1 = new HtmlElement("<P>");
child1.setStartTag("<P>");
child1.setEndTag("</P>");
child1.setTagBody("Testing html tag library");
p1.addChildTag(child1);
child1 = new HtmlElement("<P>");
child1.setStartTag("<P>");
child1.setEndTag("</P>");
child1.setTagBody("Paragraph 2");
p1.addChildTag(child1);
parentTag.generateHtml();
}
}
运行结果如下所示:
3、何时使用组合模式?
1、当您想表示对象的部分-整体层次结构时。
2、当您希望客户端能够忽略对象组合和单个对象之间的差异时。客户端将统一处理复合结构中的所有对象。