设计模式学习(七)----迭代和组合

迭代模式:

      现在考虑,一家早餐厅和一家汉堡店要合并,早餐听的菜单用来提供早餐,汉堡店中餐,

public class BreakfirstMenu{

      private List menuItem;

 

      public List getMenuItem(){

            return menuItem;

      }

      public void addMenuItem(MenuItem item){

            menu.add(item);

      }

      ...

       }

 这里认为MenuItem 有getName(),getPrice(),getDes()方法

public class HanbergerMenu{

       private MenuItem[] menuItem;

 

        public MenuItem[] getMenuItem(){

             return menuItem;

        }

         ....//set 方法the same

 }

现在要做的是waitress的事,当每天早上的时候她需要提供一份早餐单,中午午餐单,Is that so much trouble?

yes!! obvious

 

我们现在要做的是使两个菜单合并起来,It's easy . you may say. give them a interface to implements

yes that we need to do(but 只是一部分)

你能看到上面两个类的区别? 他们包含MenuItem集合的数据结构不同

对,因此两个类的get方法有区别

当waitress要遍历,比如打印菜单时需要两部走,先List在array?

怎么能把它们合成一步呢?

这里需要用到迭代器模式:

         什么是迭代器?

                JAVA中其实已经提供了迭代器Iterator,你可能已经注意到了,像List Set Vector等实现Collection接口的都有.Iterator()返回相应的迭代器,然后你就可以通过hasNext()和next()来处理

         这里我实现一个array的迭代器给HanbergerMenu使用

    public BergerIterator implements Iterator{

           private MenuItem[] menuItem;

           private int pos;

          public boolean hasNext(){

             if(pos >= menuItem.length || menuItem[pos] == null){

                      return false;

              }else{

                      return true;

             }

         }

         public Object next(){

                  MenuItem item =  menuItem[pos];

                  pos = pos + 1;

                  return item;

         }

        public void remove(){

                 throw new UnSupportException();

        }

}

其他的集合实现起来也差不多是这样

now

改一下HanbergerMenu

public class HanbergerMenu{

          public Iterator createIterator(){

                  return new BergerIterator(menuItem);

           }

  ....

}

可以在abstract Menu/Menu 接口中有createIterator() 就像Collection中一样

这样waitress在遍历是就不用些两个for循环了,只用封装一个遍历Iterator的方法,调用就行了

problem soft

更不用提,现在大部分的集合都提供了自己的Iterator实现,因此使用起来很方便都不需要实现自己的BergerIterator(数组还是要的)

甚至HashMap也可以 只要得到map.value().iterator()就行了(map.value()返回Set)

 

now I have a question?

为什么BreakfirstMenu 和HanbergerMenu不继承Menu在实现Iterator 呢?

 这里我们就再次碰到了一个OO 原则:

        单一责任,尽量使你的类保持责任单 一

Why ? 因为,单一责任,意味着变化更少,内聚更高,责任越多说明了类的变化因素越多,可能一些变动本来不会影响此类,但是因此责任牵连而此类也需要更改。

 

同时,可以看见当使用了迭代模式后,waitress不在了解Menu的数据结构,不论是array还List 对她来说都是iterator

因此使用迭代器的另一个好处是,隐藏了内部实现方式

 

组合模式:

上面的Menu 中包含了MenuItem的集合,当我们不仅需要MenuItem , 而Menu中还需要SubMenu时,怎么办

整个数据结构看上去就破坏了??

So, I think about the tree!!!

树形结构可以很好的解释上面的数据结构(SubMenu是子节点,MenuItem是leaf)

但是怎么实现它??我们要求的是:

1.能够很好的在全树的各个节点之间遍历,游走

2.和每个菜单的菜单项和子菜单之间也要能够很好的遍历

实现方式,这并不太难,使用一共公共的父类Component

public abstract class Component{

    public add(Component component);

     public remove();

    public getChild();

    public void operation();//for the MenuItem;

}

public class MenuItem implements Component{

    public void operation(){

     //....

   }

    public void add(...){

        throw unsupport...

     }

...

}

这里可以看到MenuItem的实现,只是它需要的,一些Node的方法,它不支持(throw就行了)

public class Menu implements Component{

      List components = new ArrayList();

      ....

 }

这里的Menu的包含了List<Component>

 

组合的特点:

1.以树的方式包含对象组合和个别对象的结构

2.对象的组合和个别对象实现了一样的接口,因此他们的操作一样(方法),把两者有机的结合起来,不需要区别处理,忽略了两者的区别(这是很好的一点)

 

 

再看Menu,其中包含的组合是List,万一其他的Menu不是List呢?这就是前面迭代碰到的问题

因此使用迭代来解决,把组合和迭代结合起来

public abstract class Component{

      ...

       public Iterator createIterator();

     ...

}

提供一个返回Iterator的方法

这里我在实现一个外面迭代的例子:

public class ComposistIterator implements Iterator{

   Stack stack = new Stack();

   public ComposistIterator (Iterator iterator){

       stack.push(iterator);

 }

public boolean hasNext(){

      if(stack.empty()){

         return false;

      }else{

         Iterator it = (Iterator)stack.peek();

         if(!it.hasNext()){

              stack.pop();

            return hasNext();

         }else{

          return true;

        }

       }

}

 

publc Object next(){

       if(hasNext()){

          Iterator it = (Iterator)stack.peek();

           MyComponent component = (MYComponent)it.next();

           if(component instanceof MyComponent){

                stack.push(component.createIterator));//一旦是Menu则将它的it,push到stack中

            }

              return component;

      }else{

        return null;

       }

}

 

在menuItem的createIterator()中我们可以简单的返回一个null

但是更好的一种处理是,返回一个hasNext永远是false的空迭代器

public class NullIterator implements Iterator{

    public Object next(){

           return null;

    }

     public boolean hasNext(){

           return false;

      }

    public void remove(){

 

   }

}

 

组合模式我们看到它违反了前面迭代模式讲到的单一责任原则,这又如何解释呢?

可以看到,现在不论对于wairtess还是Menu内部,MenuItem和SubMenu的操作是一样的,遍历集合的时候可以

直接操作,这就是透明性

一旦我们将责任分离了,意味着MenuItem和Menu时要不停的使用instanceof来if判断是十分麻烦的,因此组合是

牺牲一旦责任来换取透明性的一种设计模式

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值