一.组合模式简介
组合模式属于结构型模式
将组合模式合成树形结构以表示“部分-整体” 的层次结构。“Composite”使得用户对单个对象和组合对象的使用具有一致性。
适用性:
你想表示对象的部分-整体层次结构。
你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
结构:
Component 为组合中的对象声明接口。在适当情况下,实现所有类共有接口的缺省行为。声明一个接口用于访问和管理component的子组件。
leaf 在组合中表示叶节点对象,叶节点没有子节点。
composite 定义有子部件的那些不见的行为。存储子部件。在component接口中实现与子部件有关的操作。
client接口操作组合不见的对象。
组合模式分为透明模式和安全模式
透明模式:在Component中声明所有用来管 理子对象的方法,如Add()方法,Remove()方法及GetChild()方法,所有实现Component接口的子类都具备这些方法,这使得 Component和子类具备一致的行为接口,使得对客户端无需区别树叶和树枝对象。
安全模式: 在透明模式基础上把Component中声明所有用来管理子对象的方法移到Composite中,在Composite实现子对象的管理方法,那么 Leaf就没有子对象管理方法,这使得Composite和Leaf的行为接口不一致,所以客户端在调用时要知道树叶和树枝对象存在。
组合模式符合开放封闭原则,迪米特法则。
组合模式优点
高层模块调用简单:一棵属性结构中所有节点都是component,局部和整体对调用者来说没有任何区别,也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
节点自由增加:使用组合模式后,如果想增加一个树枝节点,树叶节点,只要找到它的父节点set进去就可以。对以后维护非常简单。
组合模式缺点
树枝和树叶的实现中直接使用了实现类,这在面向接口编程上是很不恰当的,与依赖倒置原则冲突。
通过继承来实现的结构型模式,一定要小心子类覆盖父类方法,因为这样可能导致整个结构的功能发生难以预知的变化。
应用场景:
维护一个树形菜单,文件系统等。
二.测试代码
1.下述代码是一种透明模式的组合模式
public class ZuhemoshiTest {
public static void main(String[] args) {
Employer employer=new ProjectManager("项目经理");
Employer employer2=new Programer("程序员1");
Employer employer3=new Programer("程序员2");
employer.add(employer2);
employer.add(employer3);
}
}
abstract class Employer{
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void add(Employer employer);
public abstract void delete(Employer employer);
public List<Employer> employers;
public void printInfo(){
System.out.println(name);
}
public List<Employer> getEmployers(){
return employers;
}
public void displayTree(Employer root) {//递归遍历整个树。
List<Employer> children = root.getEmployers();
for (Employer employer : children) {
System.out.println(employer.getName());
if(employer.getEmployers()!=null){
for(Employer employer2:employer.getEmployers()){
displayTree(employer2);
}
}
}
}
}
class Programer extends Employer{//相当于leaf
public Programer(String name){
setName(name);
employers=null;//最低端的程序员,能雇佣的只有脑子T T
}
@Override
public void add(Employer employer) {
}
@Override
public void delete(Employer employer) {
}
}
class ProjectManager extends Employer{
public ProjectManager(String name){
setName(name);
employers=new ArrayList<Employer>();
}
@Override
public void add(Employer employer) {
employers.add(employer);
}
@Override
public void delete(Employer employer) {
employers.remove(employer);
}
}
上述代码定义了一个树形结构,假如我们想定义一个employer的动作,只需要在父类中定义,全部子类重写或者直接继承即可。
2.安全模式测试代码
public class ZuhemoshiTest {
public static void main(String[] args) {
Manager manager=new ProjectManager("项目经理");
Employer employer2=new Programer("程序员1");
Employer employer3=new Programer("程序员2");
manager.add(employer2);
manager.add(employer3);
}
}
class Employer{
protected String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Programer extends Employer{//相当于leaf
public Programer(String name){
setName(name);
}
}
abstract class Manager extends Employer{
public abstract void add(Employer employer);
public abstract void delete(Employer employer);
public List<Employer> employers;
public void printInfo(){
System.out.println(name);
}
public List<Employer> getEmployers(){
return employers;
}
public void displayTree(Manager root) {
List<Employer> children = root.getEmployers();
for (Employer employer : children) {
if(employer instanceof Manager){
System.out.println(employer.getName());
displayTree((Manager)employer);
}else {
System.out.println(employer.getName());
}
}
}
}
class ProjectManager extends Manager{
public ProjectManager(String name){
setName(name);
employers=new ArrayList<Employer>();
}
@Override
public void add(Employer employer) {
employers.add(employer);
}
@Override
public void delete(Employer employer) {
employers.remove(employer);
}
}
3.为了应对组合模式没有实现面向接口编程,个人认为可以通过接口实现。核心代码如下,这个相关资料里没有提到过,不知道对不对。欢迎大神指正。
interface Employ{
public List<Employ> employs=new ArrayList<Employ>();//接口中声明的变量是final的,表示变量地址不会改变
void add(Employ employ);
void remove(Employ employ);
}