组合模式(Composite Pattern)
Posted 顧棟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组合模式(Composite Pattern)相关的知识,希望对你有一定的参考价值。
组合模式(Composite Pattern)
组合模式的定义
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
组合模式的优点
- 高层模块调用简单
树形结构的节点都是Component,使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码; - 节点自由的增加
更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;
组合模式的缺点
- 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
- 不容易限制容器中的构件;
- 不容易用继承的方法来增加构件的新功能;
- 在使用树枝和树叶时,使用了实现类,破坏了依赖倒置原则
组合模式的结构
组合模式包含以下主要角色。
- 抽象构件(Component)角色:定义了参见组合的对象的共有方法和属性,可以定义一些默认的行为和属性。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。
- 叶子构件(Leaf)角色:叶子对象,其下在没有其他分支,用于继承或实现抽象构件。
- 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。主要是组合树枝节点和叶子节点形成树形结构,它的主要作用是存储和管理子部件。
组合模式的实现
组合模式分为透明式的组合模式和安全式的组合模式。
(1) 透明方式
在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。
public interface Component {
public void add(Component c);
public void remove(Component c);
public Component getChild(int i);
public void operation();
}
public class Composite implements Component {
private ArrayList<Component> children = new ArrayList<Component>();
@Override
public void add(Component c) {
children.add(c);
}
@Override
public void remove(Component c) {
children.remove(c);
}
@Override
public Component getChild(int i) {
return children.get(i);
}
@Override
public void operation() {
for (Object obj : children) {
((Component) obj).operation();
}
}
}
public class Leaf implements Component {
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void add(Component c) {
}
@Override
public void remove(Component c) {
}
@Override
public Component getChild(int i) {
return null;
}
@Override
public void operation() {
System.out.println("树叶" + name + ":被访问!");
}
}
public static void main(String[] args) {
Component c0 = new Composite();
Component c1 = new Composite();
Component leaf1 = new Leaf("1");
Component leaf2 = new Leaf("2");
Component leaf3 = new Leaf("3");
c0.add(leaf1);
c0.add(c1);
c1.add(leaf2);
c1.add(leaf3);
c0.operation();
}
(2) 安全方式
在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。
public interface Component {
public void operation();
}
public class Composite implements Component {
private ArrayList<Component> children = new ArrayList<>();
public void add(Component c) {
this.children.add(c);
}
public void remove(Component c) {
this.children.remove(c);
}
public Component getChild(int i) {
return this.children.get(i);
}
@Override
public void operation() {
for (Object obj : children) {
((Component) obj).operation();
}
}
}
public class Leaf implements Component {
private final String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void operation() {
System.out.println("树叶" + name + ":被访问!");
}
}
public static void main(String[] args) {
Composite c0 = new Composite();
Composite c1 = new Composite();
Component leaf1 = new Leaf("1");
Component leaf2 = new Leaf("2");
Component leaf3 = new Leaf("3");
c0.add(leaf1);
c0.add(c1);
c1.add(leaf2);
c1.add(leaf3);
c0.operation();
}
(3) 其他具现使用
/**
* 树根节点
*/
public class TreeRoot {
/**
* 规则树ID
*/
private Long treeId;
/**
* 规则树根ID
*/
private Long treeRootNodeId;
/**
* 规则树名称
*/
private String treeName;
public Long getTreeId() {
return treeId;
}
public void setTreeId(Long treeId) {
this.treeId = treeId;
}
public Long getTreeRootNodeId() {
return treeRootNodeId;
}
public void setTreeRootNodeId(Long treeRootNodeId) {
this.treeRootNodeId = treeRootNodeId;
}
public String getTreeName() {
return treeName;
}
public void setTreeName(String treeName) {
this.treeName = treeName;
}
}
/**
* 树的连接线
*/
public class TreeNodeLink {
/**
* 节点From
*/
private Long nodeIdFrom;
/**
* 节点To
*/
private Long nodeIdTo;
/**
* 限定类型;1:=;2:>;3:<;4:>=;5<=;6:enum[枚举范围]
*/
private Integer ruleLimitType;
/**
* 限定值
*/
private String ruleLimitValue;
public Long getNodeIdFrom() {
return nodeIdFrom;
}
public void setNodeIdFrom(Long nodeIdFrom) {
this.nodeIdFrom = nodeIdFrom;
}
public Long getNodeIdTo() {
return nodeIdTo;
}
public void setNodeIdTo(Long nodeIdTo) {
this.nodeIdTo = nodeIdTo;
}
public Integer getRuleLimitType() {
return ruleLimitType;
}
public void setRuleLimitType(Integer ruleLimitType) {
this.ruleLimitType = ruleLimitType;
}
public String getRuleLimitValue() {
return ruleLimitValue;
}
public void setRuleLimitValue(String ruleLimitValue) {
this.ruleLimitValue = ruleLimitValue;
}
}
/**
* 树节点信息
* 叶子节点与果实节点
*/
public class TreeNode {
/**
* 规则树ID
*/
private Long treeId;
/**
* 规则树节点ID
*/
private Long treeNodeId;
/**
* 节点类型;1子叶、2果实
*/
private Integer nodeType;
/**
* 节点值[nodeType=2];果实值
*/
private String nodeValue;
/**
* 规则Key
*/
private String ruleKey;
/**
* 规则描述
*/
private String ruleDesc;
/**
* 节点链路
*/
private List<TreeNodeLink> treeNodeLinkList;
public Long getTreeId() {
return treeId;
}
public void setTreeId(Long treeId) {
this.treeId = treeId;
}
public Long getTreeNodeId() {
return treeNodeId;
}
public void setTreeNodeId(Long treeNodeId) {
this.treeNodeId = treeNodeId;
}
public Integer getNodeType() {
return nodeType;
}
public void setNodeType(Integer nodeType) {
this.nodeType = nodeType;
}
public String getNodeValue() {
return nodeValue;
}
public void setNodeValue(String nodeValue) {
this.nodeValue = nodeValue;
}
public String getRuleKey() {
return ruleKey;
}
public void setRuleKey(String ruleKey) {
this.ruleKey = ruleKey;
}
public String getRuleDesc() {
return ruleDesc;
}
public void setRuleDesc(String ruleDesc) {
this.ruleDesc = ruleDesc;
}
public List<TreeNodeLink> getTreeNodeLinkList() {
return treeNodeLinkList;
}
public void setTreeNodeLinkList(List<TreeNodeLink> treeNodeLinkList) {
this.treeNodeLinkList = treeNodeLinkList;
}
}
/**
* 聚合对象组织树的信息
*/
public class TreeRich {
/**
* 树根信息
*/
private TreeRoot treeRoot;
/**
* 树节点ID -> 子节点
*/
private Map<Long, TreeNode> treeNodeMap;
public TreeRich(TreeRoot treeRoot, Map<Long, TreeNode> treeNodeMap) {
this.treeRoot = treeRoot;
this.treeNodeMap = treeNodeMap;
}
public TreeRoot getTreeRoot() {
return treeRoot;
}
public void setTreeRoot(TreeRoot treeRoot) {
this.treeRoot = treeRoot;
}
public Map<Long, TreeNode> getTreeNodeMap() {
return treeNodeMap;
}
public void setTreeNodeMap(Map<Long, TreeNode> treeNodeMap) {
this.treeNodeMap = treeNodeMap;
}
}
/**
* 决策结果
*/
public class EngineResult {
/**
* 执行结果
*/
private boolean isSuccess;
/**
* 用户ID
*/
private String userId;
/**
* 规则树ID
*/
private Long treeId;
/**
* 果实节点ID
*/
private Long nodeId;
/**
* 果实节点值
*/
private String nodeValue;
public EngineResult() {
}
public EngineResult(boolean isSuccess) {
this.isSuccess = isSuccess;
}
public EngineResult(String userId, Long treeId, Long nodeId, String nodeValue) {
this.isSuccess = true;
this.userId = userId;
this.treeId = treeId;
this.nodeId = nodeId;
this.nodeValue = nodeValue;
}
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean success) {
isSuccess = success;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Long getTreeId() {
return treeId;
}
public void setTreeId(Long treeId) {
this.treeId = treeId;
}
public Long getNodeId() {
return nodeId;
}
public void setNodeId(Long nodeId) {
this.nodeId = nodeId;
}
public String getNodeValue() {
return nodeValue;
}
public void setNodeValue(String nodeValue) {
this.nodeValue = nodeValue;
}
}
public interface LogicFilter {
/**
* 逻辑决策器
*
* @param matterValue 决策值
* @param treeNodeLineInfoList 决策节点树
* @return 下一个节点Id
*/
public Long filter(String matterValue, List<TreeNodeLink> treeNodeLineInfoList);
/**
* 获取决策值
*
* @param decisionMatter 决策条件
* @return 决策值
*/
public String matterValue(Long treeId, String userId, Map<String, String> decisionMatter);
}
public abstract class BaseLogic implements LogicFilter {
@Override
public Long filter(String matterValue, List<TreeNodeLink> treeNodeLinkList) {
for (TreeNodeLink nodeLine : treeNodeLinkList) {
if (decisionLogic(matterValue, nodeLine)) {
return nodeLine.getNodeIdTo();
}
}
return 0L;
}
@Override
public abstract String matterValue(Long treeId, String userId, Map<String, String> decisionMatter);
private boolean decisionLogic(String matterValue, TreeNodeLink nodeLink) {
switch (nodeLink.getRuleLimitType()) {
case 1:
return matterValue.equals(nodeLink.getRuleLimitValue());
case 2:
return Double.parseDouble(matterValue) > Double.parseDouble(nodeLink.getRuleLimitValue());
case 3:
return Double.parseDouble(matterValue) < Double.parseDouble(nodeLink.getRuleLimitValue());
case 4:
return Double.parseDouble以上是关于组合模式(Composite Pattern)的主要内容,如果未能解决你的问题,请参考以下文章
设计模式之八:组合模式(Composite Pattern)
设计模式 -- 组合模式 (Composite Pattern)
尚硅谷设计模式学习(10)---[组合模式(Composite Pattern)]