组合模式

使用背景:编写程序时,我们希望将许多个体对象和组合对象组成树形结构,以此表示“部分—整体”的层次结构,并借助该层次结构使得用户能用一致的方式处理个体对象和组合对象。

组合模式使得用户对个体对象和组合对象的访问具有一致性,组合模式的关键在于无论是个体对象还是组合对象都实现了相同的接口都是同一个抽象类的子类。

个体对象:一个对象不含有其他对象的引用,具有其他子节点的节点。
组合对象:一个对象包含另外一个对象的引用,不具有其他子节点的叶节点。

角色说明
抽象组件(Component):接口或抽象类,定义了个体对象和组合对象需要实现的关于操作其子节点的方法。也可以定义个体对象和组合对象用于操作其自身的方法。

Composite节点:实现Component接口类的实例,Composite节点不仅实现Component接口,而且可以包含其他Composite节点或Leaf节点的引用。

Leaf节点:实现Component接口类的实例,Leaf节点不可以包含其他Composite节点或Leaf节点的引用。

案例:
OrganizationComponent.java

public abstract class OrganizationComponent { // 抽象组件
	private String name; // 名字
	private String des; // 说明
	
	protected void add(OrganizationComponent organizationComponent) {
		// 默认实现,之所以不是abstract的,因为抽象组件的行为不一定是所有节点都要具备的,就像这个例子里面:更多体现的是包含关系(组合关系)
		throw new UnsupportedOperationException();
	}
	
	protected void remove(OrganizationComponent organizationComponent) {
		// 默认实现,言外之意就是 要有下面的子类实现,这里不支持实现,Map集合源码里面也是这样子的(用到了组合模式)
		throw new UnsupportedOperationException();
	}
	
	public OrganizationComponent(String name,String des) {
		this.name=name;
		this.des=des;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDes() {
		return des;
	}

	public void setDes(String des) {
		this.des = des;
	}
	
	//方法print,抽象的方法,因为这个方法设计的时候是让所有节点都具备的
	protected abstract void print();
}

University.java

public class University extends OrganizationComponent{// Composite节点:大学,可以管理College
	
	//存放的是College
	List<OrganizationComponent> organizationComponentrs=new ArrayList<OrganizationComponent>();

	public University(String name, String des) {
		super(name, des);//通过父类完成构造
	}
	
	//要求所需:重写add方法
	@Override
	protected void add(OrganizationComponent organizationComponent) {
		organizationComponentrs.add(organizationComponent);
	}
	
	//重写remove方法
	@Override
	protected void remove(OrganizationComponent organizationComponent) {
		organizationComponentrs.remove(organizationComponent);
	}
	
	@Override
	public String getDes() {
		return super.getDes();
	}

	@Override
	public String getName() {
		return super.getName();
	}
	
	@Override
	protected void print() {
		System.out.println("--------"+getName()+"--------");
		
		for (OrganizationComponent organizationComponent : organizationComponentrs) {
			organizationComponent.print();
		}
	}
	
}

College.java

public class College extends OrganizationComponent{ // Composite节点:院
	
	//存放的是Department
	List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();
	
	@Override
	protected void add(OrganizationComponent organizationComponent) {
		//虽然现在看的在 University 和 College 类中的add方法的方法体完全相同,但是在实际开发中完全可能是不同的,只不过这里不做修改了。remove类似。
		organizationComponents.add(organizationComponent);
	}
	
	@Override
	protected void remove(OrganizationComponent organizationComponent) {
		organizationComponents.remove(organizationComponent);
	}

	public College(String name, String des) {
		super(name, des);
	}

	@Override
	public String getDes() {
		return super.getDes();
	}
	
	@Override
	public String getName() {
		return super.getName();
	}
	
	@Override
	protected void print() {
		System.out.println("--------"+getName()+"--------");
		
		for (OrganizationComponent organizationComponent : organizationComponents) {
			organizationComponent.print();
		}
	}
	
}

Department.java

public class Department extends OrganizationComponent{// Leaf节点:系

	public Department(String name, String des) {
		super(name, des);
	}
	
	@Override
	public String getName() {
		return super.getName();
	}
	
	@Override
	public String getDes() {
		return super.getDes();
	}

	@Override
	protected void print() {
		System.out.println(getName());
	}
	
}

Client.java

public class Client {
	public static void main(String[] args) {
		//从大到小创建对象
		University university=new University("清华大学", "Top one");
		
		//创建学院
		OrganizationComponent college1=new College("软件学院", "软件学院");
		OrganizationComponent college2=new College("计算机学院", "计算机学院");
		
		//创建各个学院下面的系(专业)
		college1.add(new Department("软件工程", "Good"));
		college1.add(new Department("网络安全工程", "Great"));
		college1.add(new Department("计算机科学与技术", "nice"));
		
		college2.add(new Department("通信工程", "hard"));
		college2.add(new Department("信息工程", "easy"));
		
		university.add(college1);
		university.add(college2);
		
//		university.print();
//		college1.print();
		
		college2.print();//从这里很明显的感觉到,组合模式真的很方便管理
		
	}
}

运行结果:
在这里插入图片描述
组合模式优点

  • 包含个体对象和组合对象,形成树形结构,使用户可以方便地处理个体对象和组合对象。
  • 个体对象和组合对象实现相同接口,用户一般无须区分个体对象和组合对象。
  • 增加新的 Composite 节点和 Leaf 节点时,用户的重要代码不需要作出改变。
  • 具有较强的扩展性,更改组合对象时,我们只需要调整内部层次关系。

适合情景

  • 想表示对象的部分-整体层次结构
  • 希望用户一致的方式处理个体对象和组合对象

如果节点和叶子有很多差异性的话,比如很多方法和属性不一样,不适合使用组合模式。

Java中的组合模式源码分析

角色说明:
抽象组件(Component):Map,AbstractMap
Composite节点:HashMap
Leaf节点:Node(HashMap的静态内部类)

分析:Map是一个interface,AbstractMap是一个Abstract class,源码的组合模式中抽象组件是这两个,AbstractMap中的 put 方法和 setValue 方法的方法体是抛出异常的,言外之意就是这个方法要由子类实现,这里不支持实现,HashMap就是实现的抽象组件的子类,在自己内部实现了 put 方法和 setValue 方法(由方法体可以看出来),在HashMap的一个静态内部类Node 类中却没有这两个方法,因为Node是叶子节点,尤其是put方法体现的更加突出,也正是因为没有put方法,即无法继续添加节点,还有在HashMap的putVal 方法中使用Node并添加到了HashMap实现类中,根据这两点就体现了Node类是Lead节点。

Map集合

public interface Map<K, V> {
     V put(K key, V value);
     V setValue(V value);
}

AbstractMap

public abstract class AbstractMap<K,V> implements Map<K,V> {
     public V put(K key, V value) {
        throw new UnsupportedOperationException();
    }

     public V setValue(V value) {
        throw new UnsupportedOperationException();
    }
}

HashMap

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

    public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
    }


}

HashMap

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;
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝朋友丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值