组合模式——HeadFirst设计模式学习笔记

组合模式:允许将对象组合成树形结构来表现“整体/部分”层次结构。组合让客户用一致的方式处理个别对象和组合对象

特点:

  • 树形结构表示对象组合
  • 忽略对象组合和对象个体之间的差别,即相同的操作既可以作用于对象组合,也可以作用与对象个体

注意:

  • 因为继承方法中,有些方法只有对叶子节点有意义,而有些方法只对非叶子节点有意义,我们可以将基类的方法默认实现为抛出UnsupportedOperationException,如果方法无意义,则无需修改默认继承就可以了

透明性:

  • 组合模式以单一责任原则换取了透明性
  • 通过让组件接口同时包含叶子节点和非叶子节点的操作,客户可以将叶子节点和非叶子节点一视同仁,客户不知道节点的类别
  • 换取透明性的同时我们同样失去了一些安全性

举例:

实现菜单中的每一項可以是菜单也可以是菜单项

抽象基类包括叶子节点和非叶子节点的全部操作默认实现为Exception

 1 public abstract class MenuComponent
 2 {
 3     //对一些方法进行了默认实现
 4     public void add(MenuComponent menuComponent)
 5     {
 6         throw new UnsupportedOperationException();
 7     }
 8     public void remove(MenuComponent menuComponent)
 9     {
10         throw new UnsupportedOperationException();
11     }
12     public MenuComponent getChild(int i)
13     {
14         throw new UnsupportedOperationException();
15     }
16     public String getName()
17     {
18         throw new UnsupportedOperationException();
19     }
20     public String getDescription()
21     {
22         throw new UnsupportedOperationException();
23     }
24     public double getPrice()
25     {
26         throw new UnsupportedOperationException();
27     }
28     public boolean isVegetarian()
29     {
30         throw new UnsupportedOperationException();
31     }
32     public void print()
33     {
34         throw new UnsupportedOperationException();
35     }
36 }  

菜单项实现,即叶子节点实现

 1 public class MenuItem extends MenuComponent
 2 {
 3     String name;
 4     String description;
 5     boolean vegetarian;
 6     double price;
 7
 8     public MenuItem(String name, String description, boolean vegetarian,double price)
 9     {
10         this.name = name;
11         this.description = description;
12         this.vegetarian = vegetarian;
13         this.price = price;
14     }
15     public String getName()
16     {
17         return name;
18     }
19     public String getDescription()
20     {
21         return description;
22     }
23     public double getPrice()
24     {
25         return price;
26     }
27     public boolean isVegetarian()
28     {
29         return vegetarian;
30     }
31     public void print()
32     {
33         System.out.print("  " + getName());
34         if (isVegetarian())//素食
35         {
36             System.out.print("(v)");
37         }
38         System.out.println(", " + getPrice());
39         System.out.println("     -- " + getDescription());
40     }
41 }  

菜单实现,即非叶子节点的实现:

 1 public class Menu extends MenuComponent
 2 {
 3     ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>();
 4     String name;
 5     String description;
 6
 7     public Menu(String name, String description)
 8     {
 9         this.name = name;
10         this.description = description;
11     }
12
13     public void add(MenuComponent menuComponent)
14     {
15         menuComponents.add(menuComponent);
16     }
17
18     public void remove(MenuComponent menuComponent)
19     {
20         menuComponents.remove(menuComponent);
21     }
22
23     public MenuComponent getChild(int i)
24     {
25         return  menuComponents.get(i);
26     }
27
28     public String getName()
29     {
30         return name;
31     }
32
33     public String getDescription()
34     {
35         return description;
36     }
37
38     public void print()
39     {
40         System.out.print("\n" + getName());
41         System.out.println(", " + getDescription());
42         System.out.println("---------------------");
43
44         Iterator iterator = menuComponents.iterator();
45         while (iterator.hasNext())
46         {
47             MenuComponent menuComponent = (MenuComponent) iterator.next();
48             menuComponent.print();
49         }
50     }
51 }

组合迭代器:

 1 public class CompositeIterator implements Iterator<MenuComponent> {
 2
 3     Stack<Iterator<MenuComponent>> stack = new Stack<Iterator<MenuComponent>>();
 4
 5
 6     public CompositeIterator(Iterator<MenuComponent> iterator) {
 7         stack.push(iterator);
 8     }
 9
10     public boolean hasNext() {
11         if (stack.empty()) {
12             return false;
13         } else {
14             Iterator<MenuComponent> iterator = (Iterator<MenuComponent>)stack.peek();
15             if (!iterator.hasNext()) {
16                 stack.pop();
17                 return hasNext(); //递归调用
18             } else {
19                 return true;
20             }
21         }
22     }
23
24     public MenuComponent next() {
25         if (hasNext()) {
26             Iterator<MenuComponent> iterator = (Iterator<MenuComponent>)stack.peek();
27             MenuComponent component = (MenuComponent)iterator.next();
28             if (component instanceof Menu) {
29                 stack.push(component.createIterator());
30             }
31             return component;
32         } else {
33             return null;
34         }
35     }
36
37     public void remove() {
38         throw new UnsupportedOperationException();
39     }
40
41 }
时间: 2024-10-16 16:02:59

组合模式——HeadFirst设计模式学习笔记的相关文章

装饰者模式——HeadFirst 设计模式学习笔记

装饰者模式:动态的将责任附加到对象上,若要扩展功能,装饰者提供了更有弹性的替代方案. 设计原则: 类的设计应该对拓展开放,对修改关闭.允许类容易拓展,在不修改现有代码的情况下添加新的行为 特点: 装饰者和被装饰对象有相同的超类型,我们利用继承达到"类型匹配",而不是利用继承获得"行为". 装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案.如果依赖继承,那么类的行为只能在编译时静态决定,行为不是来自超类就是子类覆盖后的版本,每当需

策略模式——HeadFirst 设计模式学习笔记

策略模式:策略模式定义了算法族,分别封装起来,让他们可以相互替换,此模式让算法的变化独立于使用算法的客户. 设计原则: 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起.以便以后轻松的更改或扩充此部分,而不影响不需要变化的其他部分 针对接口编程而不是针对实现编程.实际的实现不会被绑定,调用时只知道调用的接口,而无需知道具体的实现方式 多用组合,少用继承.使用组合有很大的弹性,可以在运行时动态改变行为 要点: 良好的OO设计必须遵循可复用,可拓展,可维护 大部分模式允

命令模式——HeadFirst设计模式学习笔记

命令模式:将"请求"封装成对象,以便使用不同的请求.日志.队列等来参数化其他对象.命令模式也支持撤销操作. 设计原则: 把方法的调用封装起来,调用此对象不需要知道它内部具体是如何运行的,只需要知道包装成型的方法 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开 将"动作请求者"从"动作执行者"中解耦,即将发出请求的对象和接受并执行请求的对象分离开来.两者通过命令对象沟通 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象

访问者模式——HeadFirst设计模式学习笔记

访问者模式:为某个对象组合添加新功能,而又不改变组合的内部结构 Visitor抽象访问者角色,为该对象结构中具体元素角色声明一个访问操作接口 ConcreteVisitor具体访问者角色,实现Visitor声明的接口 Element定义一个接受访问操作(accept()),它以一个访问者(Visitor)作为参数 ConcreteElement具体元素,实现了抽象元素(Element)所定义的接受操作接口 ObjectStructure结构对象角色,这是使用访问者模式必备的角色.它具备以下特性:

外观模式——HeadFirst设计模式学习笔记

外观模式:提供了一个统一的接口用来访问子系统的一群接口.外观定义了一个高层接口,让子系统更容易使用 特点: 将一个或多个类的复杂的一切隐藏在背后,只露出一个干净美好的外观 通过提供一个有着更合理接口的外观类,将复杂的子系统变得容易操作 外观只是提供了一些简化的操作,没有把子系统的高级操作隔离起来,依然将子系统完整的暴露出来,因此也可以访问子系统的接口 外观并没有实现新的行为,只是将子系统的操作合理的组合 一个子系统可以有多个外观,并可以创造分层次的外观 优点: 外观不只简化了接口,也将用户从复杂

代理模式——HeadFirst设计模式学习笔记

代理模式:为另一个对象提供一个替身或占位符控制这个对象的访问 特点: 让代理对象控制对象的访问,被代理对象可以是远程对象(远程代理),创建开销较大对象(虚拟代理),或需要安全控制的对象(保护代理) 代理分类: 远程代理:好比远程对象(在不同JVM虚拟机的对象)的本地代表(本地方法的行为转移到远程),帮助我们处理网络上的细节 代理假装自己是远程对象,不过只是一个中间角色,处理访问远程对象 Java RMI提供了客户辅助对象stub和服务辅助对象skeleton,并为其提供相同的方法 注意方法返回值

原型模式——HeadFirst设计模式学习笔记

原型模式:通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的(clone) 特点: 向用户隐藏了创建新实例的复杂性 让用户可以产生未知类型的对象,即只需知道对象实现了哪些接口,而无需知道具体是哪种实现 在某些情况下,复制对象比创建对象更高效 Prototype类需要具备以下两个条件: 实现Cloneable接口.在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone

状态模式——HeadFirst设计模式学习笔记

状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类 --将状态封装成独立的类,将动作委托给当前状态对象,所以行为会随着内部状态的变化而变化 状态转换图:为每一个状态创建一个实现一组相同操作接口的对象,实体对象包含所有状态并有一个当前状态接口的引用 特点: 允许一个对象基于不用的状态有不同的行为 把变化的东西取出来,局部化每个状态的行为,每个状态的行为局部化到自己的类中,遵守"封装变化"原则,减少了繁琐的if语句,满足"对修改关闭,对扩展开放"

中介者模式——HeadFirst设计模式学习笔记

中介者模式:集中管理相关对象之间的复杂沟通和控制     ------>>>>    特点: 关系复杂的对象之间解耦了(对象之间必须相互认识 -> 对象只认识中介者) 中介者包含了整个系统的控制逻辑,控制逻辑集中可以简化维护 每个对象在自己状态改变时告诉中介者,每个对象对中介者发出的请求给予回应 中介者常常被用来协调GUI组建 中介者需要包含所有被中介对象的引用,被中介对象可以选择是否包含中介者引用(可以在方法调用时传入) 缺点: 中介者自身可能过于复杂