GoF原文
Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.
When we need to create a structure in a way that the objects in the structure has to be treated the same way, we can apply composite design pattern. 当我们需要以同样的方式来处理结构中的对象时,我们可以应用组合设计模式。
组合模式主要有以下应用场景。
(1)希望客户端可以忽略组合对象与单个对象的差异。
(2)对象层次具备整体和部分,呈树形结构。
1. Base Component/基组件——基组件是组件中所有对象的接口。它可以是一个接口,也可以是一个抽象类,具有所有对象的一些通用方法。
2. Leaf –组成组合的各个组件,实现了基组件的功能,彼此独立没有引用关系
3. Composite – 负责管理各个组件,控制组件的调用,所有组件的功能又被基组件约束着。
Base Component
public interface A1_Shape {
public void draw(String fillColor);
}
Leaf
public class A2_Triangle implements A1_Shape {
@Override
public void draw(String fillColor) {
System.out.println("Drawing Triangle with color "+fillColor);
}
}
public class A3_Circle implements A1_Shape {
@Override
public void draw(String fillColor) {
System.out.println("Drawing Circle with color "+fillColor);
}
}
Composite
public class A4_Drawing implements A1_Shape{
private List<A1_Shape> shapes = new ArrayList<A1_Shape>();
@Override
public void draw(String fillColor) {
for(A1_Shape sh : shapes)
{
sh.draw(fillColor);
}
}
public void add(A1_Shape s){
this.shapes.add(s);
}
public void remove(A1_Shape s){
shapes.remove(s);
}
public void clear(){
System.out.println("Clearing all the shapes from drawing");
this.shapes.clear();
}
}
使用
A1_Shape tri = new A2_Triangle();
A1_Shape tri1 = new A2_Triangle();
A1_Shape cir = new A3_Circle();
A4_Drawing drawing = new A4_Drawing();
drawing.add(tri1);
drawing.add(tri1);
drawing.add(cir);
drawing.draw("Red");
drawing.clear();
drawing.add(tri);
drawing.add(cir);
drawing.draw("Green");
结果
Drawing Triangle with color Red
Drawing Triangle with color Red
Drawing Circle with color Red
Clearing all the shapes from drawing
Drawing Triangle with color Green
Drawing Circle with color Green
组合模式在JDK源码中的应用
首先来看一个非常熟悉的HashMap,它有一个putAll()方法。
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
...
public void putAll(Map<? extends K, ? extends V> m) {
putMapEntries(m, true);
}
public V remove(Object key) {
Node<K,V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
}
...
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
}
...
我们看到putAll()方法传入的是Map对象,
Map就是一个 Base Component,
而HashMap是一个Composite,
HashMap中的Node节点就是leaf。
说到 Composite 就会有规定的存储方式。HashMap中的存储使用一个静态内部类的数组Node<K,V>[],源码如下。
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
我们常用的ArrayList对象也有addAll()方法,其参数也是ArrayList的父类Collection
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
...
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
Collection<? extends E> 就是一个 Base Component,
而ArrayList是一个Composite,
存储方式 是Object[]。
那么 leaf 是什么?
没搞懂?????????????
组合对象和被组合对象都应该有统一的接口实现或者统一的抽象父类。