Combination mode (structure type)

1. What is a combination mode? A
composite mode is a behavioral mode of an object. Group objects into a tree structure to represent a "part-whole" hierarchy. The combination mode enables users to use single objects and combined objects consistently.

The essence of the combined pattern: unify the leaf object and the combined object.

The purpose of the combination mode: let the client no longer distinguish whether it is a combined object or a leaf object, but operate in a unified manner. 

 

Second, the applicability of the combination model
In development, we may often have to recursively build a tree-like combination structure, such as the following commodity category tree: 

Look closely at the commodity category tree above, which has the following obvious characteristics.

• There is a root node, such as "clothing", which has no parent node, it can contain other nodes.

• Branch nodes, a type of node can contain other nodes, called branch nodes, such as "men's clothing", "women's clothing" and "mother and baby".

• Leaf nodes. There is a type of node that has no child nodes and is called a leaf node, such as "shirt", "jacket", "skirt", "set", etc.

If you encounter something similar to the above, you need to use the object tree to describe or implement functions, you can consider using a combination of patterns, such as reading XML files, or grammatical analysis of statements.

 

Third, the structure of the combined model


The roles and responsibilities involved in the combination model are as follows:

Abstract component (Component) role: declare a common interface for combined objects and leaf objects, so that clients can access and manage the entire object tree through this interface, and can provide default implementations for these defined interfaces.
Composite object (Composite) role: usually stores subcomponents (composite objects, leaf objects), defines the behavior of those components that contain subcomponents, and implements the operations related to subcomponents defined in abstract components, such as the addition of subcomponents (addChild) and remove (removeChild) etc.
Leaf object (Leaf) role: define and implement the behavior of the leaf object, and it no longer contains other child node objects.
Client (Client) role: through the Component interface to uniformly operate the combined object and leaf object to create the entire object tree structure.

The source code of the combined mode structure is as follows:

First look at the definition of abstract component class, the sample code is as follows. 

/**
 * 抽象的组件对象,为组合中的对象声明接口,实现接口的缺省行为
 */
public abstract class Component {
 
	// 示意方法,子组件对象可能有的功能方法
	public abstract void someOperation(String preStr);
 
	public void addChild(Component child) {
		// 缺省的实现,抛出异常,因为叶子对象没有这个功能,或子类未实现这个功能
		throw new UnsupportedOperationException("对象不支持此功能");
	}
 
	public void removeChild(Component child) {
		// 缺省的实现,抛出异常,因为叶子对象没有这个功能,或子类未实现这个功能
		throw new UnsupportedOperationException("对象不支持此功能");
	}
 
	public Component getChildren(int index) {
		// 缺省的实现,抛出异常,因为叶子对象没有这个功能,或子类未实现这个功能
		throw new UnsupportedOperationException("对象不支持此功能");
	}
}

Next, look at the definition of the combined class, the schematic code is as follows. 

package composite.demo;

import java.util.ArrayList;
import java.util.List;
 
public class Composite extends Component {
	/**
	 * 用来存储组合对象中包含的子组件对象
	 */
	private List<Component> childComponents = null;

	/**
	 * 示意属性,组件的名字
	 */
	private String name = "";
 
	public Composite(String name) {
		this.name = name;
	}
 

 
	/**
	 * 示意方法,此处用于输出组件的树形结构,通常在里面需要实现递归的调用
	 */
	@Override
	public void someOperation(String preStr) {
		// 先把自己输出
		System.out.println(preStr + "+" + name);
		// 如果还包含其他子组件,那么就输出这些子组件对象
		if (null != childComponents) {
			// 添加一个空格,表示向后缩进一个空格
			preStr += "   ";
			// 输出当前对象的子组件对象
			for (Component component : childComponents) {
				// 递归地进行子组件相应方法的调用,输出每个子组件对象
				component.someOperation(preStr);
			}
		}
 
	}
 
	/**
	 * 向组合对象中添加组件对象
	 */
	public void addChild(Component child) {
		// 延迟初始化
		if (null == childComponents) {
			childComponents = new ArrayList<Component>();
		}
		childComponents.add(child);
	}
 
	/**
	 * 从组合对象中移除组件对象
	 */
	public void removeChild(Component child) {
		if (null != childComponents) {
			childComponents.remove(child);
		}
	}
 
	/**
	 * 根据索引获取组合对象中对应的组件对象
	 */
	public Component getChildren(int index) {
		if (null != childComponents) {
			if (index >= 0 && index < childComponents.size()) {
				return childComponents.get(index);
			}
		}
		return null;
	}
}

Let's take a look at the definition of the leaf class. The sample code is as follows. 

public class Leaf extends Component {
 
	/**
	 * 示意属性,组件的名字
	 */
	private String name = "";
 
	public Leaf(String name) {
		this.name = name;
	}
 
	/**
	 * 示意方法,此处用于输出组件的树形结构
	 */
	@Override
	public void someOperation(String preStr) {
		System.out.println(preStr + "-" + name);
	}
 
}

Use the Component interface in the client to operate the combined object structure, the schematic code is as follows. 

public class Client {
 
	public static void main(String[] args) {
		// 定义多个Composite组合对象
		Component root = new Composite("服装");
		Component c1 = new Composite("男装");
		Component c2 = new Composite("女装");
		Component c3 = new Composite("母婴");
 
		// 定义多个Leaf叶子对象
		Component leaf1 = new Leaf("西服");
		Component leaf2 = new Leaf("夹克");
		Component leaf3 = new Leaf("衬衫");
		Component leaf4 = new Leaf("裙子");
		Component leaf5 = new Leaf("套装");
		Component leaf6 = new Leaf("鞋袜");
		Component leaf7 = new Leaf("孕妇装");
		Component leaf8 = new Leaf("婴儿装");
 
		// 组合成为树形的对象结构
		root.addChild(c1);
		root.addChild(c2);
		root.addChild(leaf6);
		c1.addChild(leaf1);
		c1.addChild(leaf2);
		c1.addChild(leaf3);
		c2.addChild(leaf4);
		c2.addChild(leaf5);
		c2.addChild(c3);
		c3.addChild(leaf7);
		c3.addChild(leaf8);
 
		// 调用根对象的输出功能输出整棵树
		root.someOperation("");
	}
 
}

The printing result of the running program is as follows:  

+服装
   +男装
      -西服
      -夹克
      -衬衫
   +女装
      -裙子
      -套装
      +母婴
         -孕妇装
         -婴儿装
   -鞋袜

As can be seen from the above example, the key of the composition pattern lies in the role of the abstract component. As the parent class of the composite object and the leaf object, this abstract component class can represent both the leaf object and the composite object, so that when the user operates , Is always operating the component object, there is no need to distinguish between operating the combined object or the leaf object, so that the use of the leaf object and the combined object has consistency.  

 

Fourth, the security and transparency of the combination mode
The security of the combination mode refers to : whether the customer uses the combination mode to see whether it is more secure. If it is safe, then there is no possibility of misoperation, and the methods that can be accessed are the supported functions.
 • The transparency of the combination mode refers to : from the customer's use of the combination mode, it is necessary to distinguish whether it is a combination object or a leaf object. If it is transparent, then there is no need to distinguish. For the customer, it is a component object. The specific type is transparent to the customer, and the customer does not need to care.

The realization of transparency:

If the operation of managing subcomponents is defined in Component, then the client only needs to face the Component, and does not need to care about the specific component type. This implementation is the realization of transparency. The preceding structure shows that this implementation is used in the code.

But the realization of transparency comes at the cost of security, because some methods defined in Component are meaningless for leaf objects, such as adding and deleting child component objects. However, these methods are transparent to the client, so the client may call this method of adding or deleting child components to the leaf object. Such operations are not safe.

The common way to achieve the transparency of the combined mode is to declare the operation of the subcomponents in the Component and provide default implementations for these methods in the Component. For functions that are not supported by the leaf object, you can directly throw an exception to Indicates that this feature is not supported.

Implementation of security: 

If the operation of managing subcomponents is defined in Composite, then when the client uses the leaf object, the operation of adding subcomponents or deleting subcomponents will not occur, because there is no such function at all, this implementation The way is safe.

But in this way, when the client uses it, it must distinguish whether it is a Composite object or a leaf object. The functions of different objects are different.

Choice of two implementation methods:

For the combined mode, in terms of security and transparency, it will pay more attention to transparency. After all, the function of the combined mode is to make the user use the leaf object and the combined object consistent.

Therefore, when using the combined mode, you should use more transparent implementations and less security implementations. 

 

Fifth, the advantages and disadvantages of the combination mode The advantages of
using the combination mode:

  1) Unify the combined objects and leaf objects.
              2) The client call is simplified, and it is not necessary to distinguish whether the operation is a combined object or a leaf object.
              3) It is easier to extend. With the constraints of Component, the newly defined Composite or Leaf subclass can easily work with the existing structure.

Disadvantages of using the combination mode: It is difficult to limit the types of components in the combination. 

 

6. Summary The
combination mode treats the leaf object as a special combined object, so that the leaf object and the combined object are treated equally, and all of them are regarded as Component objects. The leaf object and the combined object are unified organically.

It is precisely because the leaf object and the combined object are unified that there is no need to distinguish when constructing the object into a tree structure. Anyway, the component object contains other component objects, so recursion continues: it also makes the tree structure The operation becomes simple, regardless of the object type, unified operation. 

Published 138 original articles · praised 34 · 150,000 views

Guess you like

Origin blog.csdn.net/bbj12345678/article/details/105179671