组合模式(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.