复合设计模式(Composite Design Pattern)


目的
它属于structural 设计模式目录。将对象组合成树结构以表示部分整体层次结构。Composite允许客户端统一处理单个对象和对象组合。

解释
现实世界的例子
每个句子都由单词组成,而单词又由字符组成。这些对象中的每一个都是可打印的,并且它们可以在它们之前或之后打印一些东西,例如句子总是以句号结束并且字总是在它之前有空格。
简单来说
复合模式允许客户以统一的方式处理单个对象。
维基百科说
在软件工程中,复合模式是一种分区设计模式。复合模式描述一组对象将以与单个对象实例相同的方式进行处理。组合的目的是将对象“组合”到树结构中,以表示 部分— 整体 层次结构。通过实现复合模式,客户可以统一处理单个对象和组合。

结构

参与者
1.组件Component

  • 声明组合中对象的接口。

  • 根据需要,为所有类共有的接口实现默认行为。

  • 声明用于访问和管理其子组件的接口。

  • (可选)在递归结构中定义用于访问组件父级的接口,并在适当的情况下实现它。。

2.叶子 Leaf 
  • 表示组合中的叶子对象。叶子没有子类。

  • 定义合成中基本对象的行为。

3.组合Composite
  • 定义具有子项的组件的行为。

  • 存储子组件。

  • 在Component接口中实现与子相关的操作。

4.客户端Client
  • 通过Component 接口操作组合中的对象  。

合作

  • 客户端使用Component类接口与组合结构中的对象进行交互。如果收件人是Leaf,则直接处理请求。如果收件人是Composite,则它通常将请求转发给其子组件,可能在转发之前和/或之后执行其他操作。 

源代码(示例1)
以我们上面的句子为例。这里有基类和不同的可打印类型
public abstract class LetterComposite {
  private List<LetterComposite> children = new ArrayList<>();
  public void add(LetterComposite letter) {
    children.add(letter);
  }
  public int count() {
    return children.size();
  }
  protected void printThisBefore() {}
  protected void printThisAfter() {}
  public void print() {
    printThisBefore();
    for (LetterComposite letter : children) {
      letter.print();
    }
    printThisAfter();
  }
}

public class Letter extends LetterComposite {
  private char c;
  public Letter(char c) {
    this.c = c;
  }
  @Override
  protected void printThisBefore() {
    System.out.print(c);
  }
}

public class Word extends LetterComposite {
  public Word(List<Letter> letters) {
    for (Letter l : letters) {
      this.add(l);
    }
  }
  @Override
  protected void printThisBefore() {
    System.out.print(" ");
  }
}

public class Sentence extends LetterComposite {
  public Sentence(List<Word> words) {
    for (Word w : words) {
      this.add(w);
    }
  }
  @Override
  protected void printThisAfter() {
    System.out.print(
".");
  }
}

然后我们有一个信使来传递信息

public class Messenger {
  LetterComposite messageFromOrcs() {
    List<Word> words = new ArrayList<>();
    words.add(new Word(Arrays.asList(new Letter('W'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
    words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
    words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
    words.add(new Word(Arrays.asList(new Letter('a'))));
    words.add(new Word(Arrays.asList(new Letter('w'), new Letter('h'), new Letter('i'), new Letter('p'))));
    words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
    words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
    words.add(new Word(Arrays.asList(new Letter('a'))));
    words.add(new Word(Arrays.asList(new Letter('w'), new Letter('a'), new Letter('y'))));
    return new Sentence(words);
  }

  LetterComposite messageFromElves() {
    List<Word> words = new ArrayList<>();
    words.add(new Word(Arrays.asList(new Letter('M'), new Letter('u'), new Letter('c'), new Letter('h'))));
    words.add(new Word(Arrays.asList(new Letter('w'), new Letter('i'), new Letter('n'), new Letter('d'))));
    words.add(new Word(Arrays.asList(new Letter('p'), new Letter('o'), new Letter('u'), new Letter('r'), new Letter('s'))));
    words.add(new Word(Arrays.asList(new Letter('f'), new Letter('r'), new Letter('o'), new Letter('m'))));
    words.add(new Word(Arrays.asList(new Letter('y'), new Letter('o'), new Letter('u'), new Letter('r'))));
    words.add(new Word(Arrays.asList(new Letter('m'), new Letter('o'), new Letter('u'), new Letter('t'), new Letter('h'))));
    return new Sentence(words);
  }
}

然后它可以用作

LetterComposite orcMessage = new Messenger().messageFromOrcs();
orcMessage.print(); // Where there is a whip there is a way.
LetterComposite elfMessage = new Messenger().messageFromElves();
elfMessage.print();
// Much wind pours from your mouth.

源代码(例2)
步骤1:  创建 将被视为组件Component的  Employee 接口  。

/ this is the Employee interface i.e. Component.  
public interface Employee {  
    public  int getId();  
    public String getName();  
    public double getSalary();  
       public void print();  
    public void add(Employee employee);  
       public void remove(Employee employee);  
       public Employee getChild(int i);  
}// End of the Employee interface. 

第2步:  创建一个 将被视为Composite 的  BankManager 类,   并实现Employee接口。

// this is the BankManager class i.e. Composite.  
import java.util.ArrayList;  
import java.util.Iterator;  
import java.util.List;  
public class BankManager implements Employee {  
     private int id;  
     private String name;  
     private double salary;  
  
     public BankManager(int id,String name,double salary) {  
      this.id=id;      
      this.name = name;  
      this.salary = salary;  
     }  
         List<Employee> employees = new ArrayList<Employee>();  
     @Override  
     public void add(Employee employee) {  
        employees.add(employee);  
     }  
        @Override  
     public Employee getChild(int i) {  
      return employees.get(i);  
     }  
     @Override  
     public void remove(Employee employee) {  
      employees.remove(employee);  
     }    
     @Override  
     public int getId()  {  
      return id;  
     }  
     @Override  
     public String getName() {  
      return name;  
     }  
    @Override  
     public double getSalary() {  
      return salary;  
     }  
     @Override  
     public void print() {  
      System.out.println(
"==========================");  
      System.out.println(
"Id ="+getId());  
      System.out.println(
"Name ="+getName());  
      System.out.println(
"Salary ="+getSalary());  
      System.out.println(
"==========================");  
        
      Iterator<Employee> it = employees.iterator();  
        
          while(it.hasNext())  {  
            Employee employee = it.next();  
            employee.print();  
         }  
     }  
}
// End of the BankManager class.  

第3步:  创建一个 将被视为叶子leaf 的  Cashier 类,   它将实现到Employee接口。

public  class Cashier implements Employee{  
    /* 
         In this class,there are many methods which are not applicable to cashier because 
         it is a leaf node. 
     */
 
        private int id;  
            private String name;  
        private double salary;  
        public Cashier(int id,String name,double salary)  {  
            this.id=id;  
            this.name = name;  
            this.salary = salary;  
        }  
        @Override  
        public void add(Employee employee) {  
           
//this is leaf node so this method is not applicable to this class.  
        }  
        @Override  
        public Employee getChild(int i) {  
           
//this is leaf node so this method is not applicable to this class.  
            return null;  
        }  
        @Override  
        public int getId() {  
           
// TODO Auto-generated method stub  
            return id;  
        }  
        @Override  
        public String getName() {  
            return name;  
        }  
        @Override  
        public double getSalary() {  
            return salary;  
        }  
        @Override  
        public void print() {  
            System.out.println(
"==========================");  
            System.out.println(
"Id ="+getId());  
            System.out.println(
"Name ="+getName());  
            System.out.println(
"Salary ="+getSalary());  
            System.out.println(
"==========================");  
        }  
        @Override  
        public void remove(Employee employee) {  
           
//this is leaf node so this method is not applicable to this class.  
        }  
}  

第4步:  创建一个  Accountant  类,它也将被视为一个 leaf,它将实现到Employee接口。

public class Accountant implements Employee{  
/* 
    In this class,there are many methods which are not applicable to cashier because 
    it is a leaf node. 
*/
 
    private int id;  
    private String name;  
    private double salary;  
   public Accountant(int id,String name,double salary)  {  
       this.id=id;  
       this.name = name;  
       this.salary = salary;  
   }  
   @Override  
   public void add(Employee employee) {  
       
//this is leaf node so this method is not applicable to this class.  
   }  
   @Override  
   public Employee getChild(int i) {  
       
//this is leaf node so this method is not applicable to this class.  
       return null;  
   }  
   @Override  
    public int getId() {  
       
// TODO Auto-generated method stub  
        return id;  
   }  
   @Override  
   public String getName() {  
       return name;  
   }  
   @Override  
   public double getSalary() {  
       return salary;  
   }  
   @Override  
   public void print() {  
       System.out.println(
"=========================");  
       System.out.println(
"Id ="+getId());  
       System.out.println(
"Name ="+getName());  
       System.out.println(
"Salary ="+getSalary());  
       System.out.println(
"=========================");  
   }  
  @Override  
   public void remove(Employee employee) {  
       
//this is leaf node so this method is not applicable to this class.  
   }  
}  

步骤5:  创建一个  CompositePatternDemo  类,该类也将被视为 客户端 Client ,ii将使用Employee接口。

public class CompositePatternDemo {  
    public static void main(String args[]){  
         Employee emp1=new Cashier(101,"Sohan Kumar", 20000.0);  
         Employee emp2=new Cashier(102,
"Mohan Kumar", 25000.0);  
         Employee emp3=new Accountant(103,
"Seema Mahiwal", 30000.0);   
         Employee manager1=new BankManager(100,
"Ashwani Rajput",100000.0);  
            
          manager1.add(emp1);  
          manager1.add(emp2);  
          manager1.add(emp3);  
          manager1.print();  
        }  
}  

适用性
使用复合模式时

  • 您想要表示对象的 部分— 整体 层次结构

  • 您希望客户能够忽略对象组合和单个对象之间的差异。客户端将统一处理复合结构中的所有对象