组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
如果不使用组合模式,客户端代码将过多地依赖于容器对象复杂的内部实现结构,容器对象内部实现结构的变化将引起客户代码的频繁变化,带来了代码维护复杂、可扩展性差等弊端。组合模式的引入将在一定程度上解决这些问题。
代码实现
public abstract class OrganizationComponet {
private String name;
private String des;
protected void add(OrganizationComponet organizationComponet) {
throw new UnsupportedOperationException();
}
protected void remove(OrganizationComponet organizationComponet) {
throw new UnsupportedOperationException();
}
public OrganizationComponet(String name, String des) {
super();
this.name = name;
this.des = des;
}
//print
protected abstract void print();
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;
}
@Override
public String toString() {
return "OrganizationComponet [name=" + name + ", des=" + des + "]";
}
public OrganizationComponet() {
super();
}
}
///university 就是Composite,可以管理College
public class University extends OrganizationComponet{
List<OrganizationComponet> organizationComponets = new ArrayList<OrganizationComponet>();
//构造器
public University(String name, String des) {
super(name, des);
// TODO Auto-generated constructor stub
}
@Override
protected void add(OrganizationComponet organizationComponet) {
organizationComponets.add(organizationComponet);
}
@Override
protected void remove(OrganizationComponet organizationComponet) {
// TODO Auto-generated method stub
organizationComponets.remove(organizationComponet);
}
@Override
public String getDes() {
// TODO Auto-generated method stub
return super.getDes();
}
@Override
public String getName() {
// TODO Auto-generated method stub
return super.getName();
}
//输出university中包含的学院
@Override
protected void print() {
System.out.println("----------"+getName()+"----------");
for (OrganizationComponet o :organizationComponets){
o.print();
}
}
}
public class College extends OrganizationComponet {
List<OrganizationComponet> organizationComponets = new ArrayList<OrganizationComponet>();
//构造器
public College(String name, String des) {
super(name, des);
// TODO Auto-generated constructor stub
}
@Override
protected void add(OrganizationComponet organizationComponet) {
organizationComponets.add(organizationComponet);
}
@Override
protected void remove(OrganizationComponet organizationComponet) {
// TODO Auto-generated method stub
organizationComponets.remove(organizationComponet);
}
@Override
public String getDes() {
// TODO Auto-generated method stub
return super.getDes();
}
@Override
public String getName() {
// TODO Auto-generated method stub
return super.getName();
}
//输出学院包含的系
@Override
protected void print() {
System.out.println("----------"+getName()+"----------");
for (OrganizationComponet o :organizationComponets){
o.print();
}
}
}
public class Departent extends OrganizationComponet{
public Departent(String name,String des) {
super(name,des);
}
//add,remove 不需要在写,因为他是叶子节点
@Override
protected void print() {
System.out.println(getName());
}
@Override
public String getName() {
// TODO Auto-generated method stub
return super.getName();
}
@Override
public String getDes() {
// TODO Auto-generated method stub
return super.getDes();
}
}
public class Cilents {
public static void main(String[] args) {
//从大到小创建
//学校
OrganizationComponet university = new University("清华大学","顶级大学");
//学院
OrganizationComponet college1 = new College("计算机学院","计算机学院");
OrganizationComponet college2 = new College("理学院","理学院");
//专业
college1.add(new Departent("软件工程","不错"));
college1.add(new Departent("网络工程","不错"));
college1.add(new Departent("计算机科学与技术","老排不错"));
college2.add(new Departent("通信工程","发发发不错"));
college2.add(new Departent("信息工程","很好学不错"));
//将学院加入到学校
university.add(college1);
university.add(college2);
university.print();
System.out.println("===============================");
college1.print();
}
}
抽象构件角色
一般将抽象构件类设计为接口或抽象类,将所有子类共有方法的声明和实现放在抽象构件类中。对于客户端而言,将针对抽象构件编程,而无须关心其具体子类是容器构件还是叶子构件。
public abstract class Component {
/**
* 增加成员
* @param c
*/
public void add(Component c){
throw new UnsupportedOperationException();
}
/**
* 删除成员
* @param c
*/
public void remove(Component c){
throw new ();
}
/**
* 获取成员
* @param i
* @return
*/
public Component getChild(int i){
throw new ();
}
/**
* 业务方法
*/
public void operation(){
throw new ();
}
}
叶子构件
public class Leaf extends Component {
@Override
public void operation(){
System.out.println("子构件");
}
}
容器构件
public class Composite extends Component {
private List<Component> list = new ArrayList<Component>();
@Override
public void add(Component c){
list.add(c);
}
@Override
public void remove(Component c) {
list.remove(c);
}
@Override
public Component getChild(int i) {
return list.get(i);
}
@Override
public void operation(){
for (Component child: list){
child.operation();
}
}
}
总结
使用组合模式可以让用户可以使用统一的方式处理整个树形结构的个别对象和组合对象,从而简化客户端的操作。
组合模式具有较强的扩展性,当我们想要更改组合对象时,只需要调整内部的层次关系即可,客户端不需要作出任何改动。
客户端不用考虑组合中的细节,通过添加节点和叶子就可以创建出复杂的树形结构。
当需要处理的对象是树形结构时可以考虑使用组合模式。
节点和叶子节点存在很大差异的情况下不建议使用组合模式。
通过案例了解组合模式
深圳某公司总部使用的OA系统,由于简单易用,反响良好的原因,准备被推广到各分公司使用。
关于组织结构的设计,原来是这样的:一个公司总部下面有人力资源部、财务部等。
// 组织
public interface Organization {
void addOrg(Department department);
void removeOrg(Department department);
String getName();
void showOrg();
void displayDuty();
}
// 公司总部
public class Headquarters implements Organization {
private List<Department> departments = new ArrayList<>();
@Override
public void addOrg(Department department) {
departments.add(department);
}
@Override
public void removeOrg(Department department) {
departments.remove(department);
}
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public void showOrg() {
System.out.println("-" + getName());
for (Department department : departments) {
System.out.println("--" + department.getName());
}
}
@Override
public void displayDuty() {
for(Department department : departments) {
department.duty();
}
}
}
// 部门
public interface Department {
String getName();
void duty();
}
// 财务部
public class FinanceDepartment implements Department {
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public void duty() {
System.out.println("财务部负责公司财务收支管理");
}
}
// 人力资源部
public class HumanResourceDepartment implements Department{
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public void duty() {
System.out.println("人力资源部负责员工招聘培训管理");
}
}
// 测试类
public class Before {
public static void main(String[] args) {
Organization hq = new Headquarters();
Department fnc = new FinanceDepartment();
Department hr = new HumanResourceDepartment();
hq.addOrg(fnc);
hq.addOrg(hr);
System.out.println("====组织结构====");
hq.showOrg();
System.out.println("====部门职责====");
hq.displayDuty();
}
}
应用组合模式的代码
// 公司组织或部门
public interface Company {
void addOrg(Company company);
void removeOrg(Company company);
void showOrg(int depth);
default void print(int dept) {
while(dept-- > 0) {
System.out.print("-");
}
}
}
// 总部或分公司
public class ConcreteComp implements Company {
private String name = "";
private List<Company> companies = new ArrayList<>();
ConcreteComp(String name) {
this.name = name;
}
@Override
public void addOrg(Company company) {
companies.add(company);
}
@Override
public void removeOrg(Company company) {
companies.remove(company);
}
@Override
public void showOrg(int dept) {
print(dept);
System.out.println(this.name);
for (Company c : companies) {
c.showOrg(dept + 2);
}
}
}
// 财务部
public class FinanceDepartment implements Company {
private String name = "";
FinanceDepartment(String name) {
this.name = name;
}
@Override
public void addOrg(Company company) {
}
@Override
public void removeOrg(Company company) {
}
@Override
public void showOrg(int dept) {
print(dept);
System.out.println(this.name);
}
}
// 人力资源部
public class HumanResourceDepartment implements Company {
private String name = "";
HumanResourceDepartment(String name) {
this.name = name;
}
@Override
public void addOrg(Company company) {
}
@Override
public void removeOrg(Company company) {
}
@Override
public void showOrg(int dept) {
print(dept);
System.out.println(this.name);
}
}
// 测试类
public class After {
public static void main(String[] args) {
Company headquarters = new ConcreteComp("公司总部");
headquarters.addOrg(new FinanceDepartment("财务部"));
headquarters.addOrg(new HumanResourceDepartment("人力资源部"));
Company gd = new ConcreteComp("广东分公司");
gd.addOrg(new FinanceDepartment("财务部"));
gd.addOrg(new HumanResourceDepartment("人力资源部"));
Company sz = new ConcreteComp("深圳分公司");
sz.addOrg(new FinanceDepartment("财务部"));
sz.addOrg(new HumanResourceDepartment("人力资源部"));
gd.addOrg(sz);
Company sh = new ConcreteComp("上海分公司");
sh.addOrg(new FinanceDepartment("财务部"));
sh.addOrg(new HumanResourceDepartment("人力资源部"));
headquarters.addOrg(gd);
headquarters.addOrg(sh);
headquarters.showOrg(1);
Company test = new FinanceDepartment("测试财务部");
test.addOrg(new HumanResourceDepartment("测试人力资源部"));
test.addOrg(sh);
test.showOrg(1);
}
}
透明方式与安全方式
上面应用组合模式的方式就是透明方式,接口Company定义了addOrg、removeOrg方法,无论是叶子角色还是树枝角色都拥有addOrg、removeOrg方法,从实际使用的角度来说,叶子角色不需要这两个方法。对于外界来说,叶子和树枝的区别是透明的,这就是透明方式。
安全方式就是接口Company里没有定义addOrg、removeOrg方法,只在树枝角色添加addOrg、removeOrg方法。这样用户需要对叶子角色和树枝角色进行判断能不能使用ddOrg、removeOrg方法。
透明方式的缺点是叶子角色在添加叶子或者树枝时是什么也不做,用户觉得应该是操作成功了,但是并没有操作成功。安全方式的缺点就是在添加叶子和树枝的时候需要进行判断。