发布于2021-05-29 23:58 阅读(1164) 评论(0) 点赞(13) 收藏(4)
使用背景:编写程序时,我们希望将许多个体对象和组合对象组成树形结构,以此表示“部分—整体”的层次结构,并借助该层次结构使得用户能用一致的方式处理个体对象和组合对象。
组合模式使得用户对个体对象和组合对象的访问具有一致性,组合模式的关键在于无论是个体对象还是组合对象都实现了相同的接口都是同一个抽象类的子类。
个体对象:一个对象不含有其他对象的引用,具有其他子节点的节点。
组合对象:一个对象包含另外一个对象的引用,不具有其他子节点的叶节点。
角色说明
抽象组件(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();//从这里很明显的感觉到,组合模式真的很方便管理
}
}
运行结果:
组合模式优点
适合情景
如果节点和叶子有很多差异性的话,比如很多方法和属性不一样,不适合使用组合模式。
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;
}
}
原文链接:https://blog.csdn.net/qq_45697630/article/details/117265701
作者:我睡觉爱打呼噜
链接:http://www.javaheidong.com/blog/article/207969/c240553ace6ff3f02ac3/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!