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

组合模式(Composite Pattern)

听名字就像是把什么东西组合在一起的设计模式,所以

组合模式就是将两个类中的一些共同的方法抽象在一起

然而,很多时候,一些类中的方法很明显会不一样,这里,感觉 headfirst 上那个例子就挺好的,然后我做了下修改。

public interface MenuItem {
    String getName();
    void print();
    String getText();
}

首先去设计一个菜单选项,一些和菜单公有的方法,获得名字,打印一些东西,和自己独有的方法,获得菜单选项上要显示的内容,这样看起来并没有什么不好。
不过当设计菜单的时候

public interface Menu {
    String getName();
    void print();
    void add(Menu menu);
    void add(MenuItem menuItem);
    void remove(Menu menu);
    void remove(MenuItem menuItem);
}

这个感觉就像我可以新建一个文件夹,文件夹里面可以去放文件夹或者文件,这样的话基本上每一个操作都会成对出现,我们也没办法让一个文件继承自一个文件夹,而且对于 getChildAt 这种方法的实现,还是要菜单和菜单选项继承同一个父类,就算是用泛型也感觉相当不好,这种情况下就要用组合模式了。

public interface View {
    String getName();
    void print();
    String getText();
    void add(View view);
    void remove(View view);
    View getChildAt(int index);
}

把它们公有和特有的部分全都抽象出来,然后分别实现这个接口。等等,那些没用的方法怎么办,还是先用抽象类实现默认方法吧。

public abstract class ViewComponent implements View {
    protected String mName;

    @Override
    public String getName() {
        return mName;
    }

    @Override
    public void print() {
        System.out.println(mName);
    }

    @Override
    public String getText() {
        throw new RuntimeException("no text");
    }

    @Override
    public void add(View view) {
        throw new RuntimeException("no child");
    }

    @Override
    public void remove(View view) {
        throw new RuntimeException("no child");
    }

    @Override
    public View getChildAt(int index) {
        throw new RuntimeException("no child");
    }

    @Override
    public int getChildCount() {
        throw new RuntimeException("no child");
    }
}

如果没办法操作的话默认抛异常,然后分别继承这个类去重写方法。

public class MenuItem extends ViewComponent {
    private String mText;
    public MenuItem(String name, String text) {
        mName = name;
        mText = text;
    }

    @Override
    public void print() {
        System.out.println("item: " + mName + ", " + mText);
    }

    @Override
    public String getText() {
        return mText;
    }
}
public class Menu extends ViewComponent {
    private List<View> mData = new ArrayList<View>();

    public Menu(String name) {
        mName = name;
    }

    @Override
    public void print() {
        System.out.println("menu: " + mName);
        for (View view : mData) {
            view.print();
        }
    }

    @Override
    public int getChildCount() {
        return mData.size();
    }

    @Override
    public View getChildAt(int index) {
        return mData.get(index);
    }

    @Override
    public void add(View view) {
        mData.add(view);
    }

    @Override
    public void remove(View view) {
        mData.remove(view);
    }
}

这个的测试代码写起来比较麻烦 - -

public class Main {
    public static void main(String[] args) {
        View menu1 = new Menu("menu1");
        View menuItem11 = new MenuItem("menuItem11", "11");
        menu1.add(menuItem11);
        View menuItem12 = new MenuItem("menuItem12", "12");
        menu1.add(menuItem12);
        View menu11 = new Menu("menu11");
        menu1.add(menu11);
        View menuItem111 = new MenuItem("menuItem111", "111");
        menu11.add(menuItem111);
        menu1.print();
    }
}

这样的话就通过 View 进行操作,但很明显操作变得不安全了,但在使用部分,可以省去很多 if 之类的判断,所以呢,这种设计模式的使用需要慎重一点吧。

The end.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值