android 设计模式-组合模式

组合设计模式让我们能用树形方式创建对象的结构,树里面包含了组合及个别的对象。是用组合结构,我们能把相同的操作应用在组合和个别对象上。话句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。

---------援引自《Head First》

接着前面所写的迭代器模式,现在需要给午餐加一个子菜单。此时结构如下图所示:


(如果是我来做,我可能会在MenuItem里面再加个list 或者 array ,但仅仅是构思一下就觉得很头痛。)

不能把子菜单赋值给午餐菜单的item。因为午餐菜单的item的类型是MenuItem,子菜单的类型可能是list或者数组或者map,但不是MenuItem。现在代码需要重新构思,我们需要的设计是能够实现:

1.需要树形结构,可以容纳菜单、子菜单、菜单项。

2.我们需要能够在每个菜单的各个项之间游走。

3.我们也需要能够弹性的再菜单项之间游走。

我们的菜单结构就像这下面树形结构的草图:


关于上面第一条无须解释,关于第二条,意思就是我们能够遍历所有的菜单项,就像上图左下角的图所示。关于第三条,意思是说,我们可以灵活的选择去遍历我们想要遍历的那个菜单,比如说只去遍历图中众多菜单中的DinnerMenu,就像上图右下角所所示。

关于树形结构,具有子元素的节点叫做“节点”,没有子元素的节点叫做“叶节点”,我们可以把一个大树视为一个整体来操作,也可以把树中的“小树”当做一个小的整体来操作。(就像你可以命令一个团做一件事,也可以从这个团中抽出一个连,命令这个连做同样的事)。

关于组合模式类图:


抽象出来是这样的。leaf就是叶节点,对应的就是MenuItem这个小虾米,composite就是节点,对应的是菜单,这里composite定义组合节点的行为,leaf定义了组合内元素的行为,leaf 和 composite 都实现了接口中的一些方法,但对于各自来说有些方法是没有意义的,毕竟内部结构不同。针对我们要做的需求来说,与上图结构相同,只是接口中方法需要重新构思。接口里需要有getName(),getPrice(),getChild(int),isVegetarian()等方法,对于菜单来说isVegetarian()是没有意义的(你无法说一个菜单是素的还是荤的,因为这是菜的属性)。所以说leaf 和 composite不需要实现接口里全部的方法,而且我们希望这个接口可以提供这些方法的默认实现,于是我们可以把这个接口定义为抽象类,书里管这个类叫做“菜单组件”。

public abstract class MenuComponent {

    public void add(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public void remove(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public void print(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public MenuComponent getChild(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public String getName(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public String getDescription(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public boolean isVegetrarian(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public double getPrice(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }
}

我们的菜单项和菜单,即“叶节点”和“”节点需要继承MenuComponent来实现组合内元素的行为和组合的行为。

package com.buxiaohui.menu;

import android.util.Log;

import java.util.ArrayList;


public class MenuItem extends MenuComponent {
    private ArrayList menuComponent = new ArrayList();
    private String name;
    private String description;
    private boolean vegetarian;
    private double price;

    public MenuItem(String name, String description, boolean vegetarian, double price) {
        this.name = name;
        this.description = description;
        this.vegetarian = vegetarian;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public void setVegetarian(boolean vegetarian) {
        this.vegetarian = vegetarian;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public void print() {
        Log.d("debug", "name = " + getName());
        if (isVegetarian()) {
            Log.d("debug", "(V)");
        }
        Log.d("debug", "price=" + getPrice());
        Log.d("debug", "desc=" + getDescription());
        Log.d("debug","===============");

    }
}


package com.buxiaohui.menu;

import android.util.Log;

import java.util.ArrayList;
import java.util.Iterator;


public class CommonMenu extends MenuComponent {
    ArrayList menuComponents = new ArrayList();
    String name;
    String description;

    public CommonMenu(String name, String description) {
        this.name = name;
        this.description = description;

    }

    public void add(MenuComponent menuComponent) {
        menuComponents.add(menuComponent);
    }

    public void remove(MenuComponent menuComponent) {
        menuComponents.remove(menuComponent);
    }

    public void print() {
        Log.d("debug", "name = " + getName());
        Log.d("debug","desc=" + getDescription());
        Log.d("debug","=====================================");
        Iterator iterator = menuComponents.iterator();
        while(iterator.hasNext()){
            MenuComponent menuComponent = (MenuComponent)iterator.next();
            menuComponent.print();
        }
    }

    public MenuComponent getChild(int i) {
        return (MenuComponent)menuComponents.get(i);
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

}
====MainActivity====

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MenuComponent menuComponent0 = new CommonMenu("早餐-菜单","我是早餐菜单");
        MenuComponent menuComponent1 = new CommonMenu("午餐-菜单","我是午餐菜单");
        MenuComponent menuComponent2 = new CommonMenu("甜点-菜单","我是甜点菜单");
        MenuComponent allMenus = new CommonMenu("All Menus","All Menus!");
        allMenus.add(menuComponent0);
        allMenus.add(menuComponent1);
        allMenus.add(menuComponent2);
        menuComponent0.add(new com.buxiaohui.menu.MenuItem("早餐0","test0-name0000000000",true,100.00));
        menuComponent0.add(new com.buxiaohui.menu.MenuItem("早餐1","test0-name1111111111",true,100.01));
        menuComponent2.add(new com.buxiaohui.menu.MenuItem("甜点0","甜点0甜点0甜点0",true,100.00));
        menuComponent2.add(new com.buxiaohui.menu.MenuItem("甜点1","甜点1甜点1甜点1",true,101.01));
        menuComponent2.add(new com.buxiaohui.menu.MenuItem("甜点2","甜点2甜点2甜点2",true,102.02));
        menuComponent2.add(new com.buxiaohui.menu.MenuItem("甜点3","甜点3甜点3甜点3",true,103.03));
        menuComponent0.add(menuComponent2);
        menuComponent1.add(menuComponent2);
        Waitress waitress = new Waitress(allMenus);
        waitress.print();

    }

}
=======运行结果=====
运行结果显示,早餐菜单除了若干个菜单项(MenuItem),还有子菜单也打印出来了。

05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = All Menus
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=All Menus!
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ =====================================
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 早餐-菜单
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=我是早餐菜单
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ =====================================
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 早餐0
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=100.0
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=test0-name0000000000
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 早餐1
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=100.01
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=test0-name1111111111
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点-菜单
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=我是甜点菜单
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ =====================================
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点0
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=100.0
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点0甜点0甜点0
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点1
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=101.01
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点1甜点1甜点1
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点2
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=102.02
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点2甜点2甜点2
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点3
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.470  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=103.03
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点3甜点3甜点3
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 午餐-菜单
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=我是午餐菜单
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ =====================================
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点-菜单
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=我是甜点菜单
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ =====================================
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点0
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=100.0
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点0甜点0甜点0
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点1
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=101.01
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点1甜点1甜点1
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点2
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=102.02
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点2甜点2甜点2
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点3
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=103.03
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点3甜点3甜点3
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点-菜单
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=我是甜点菜单
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ =====================================
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点0
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=100.0
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点0甜点0甜点0
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点1
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=101.01
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点1甜点1甜点1
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点2
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=102.02
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点2甜点2甜点2
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ name = 甜点3
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ (V)
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ price=103.03
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ desc=甜点3甜点3甜点3
05-25 13:57:45.471  20011-20011/com.buxiaohui.myapplication D/debug﹕ ===============
05-25 13:57:45.472  20011-20011/com.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值