深入浅出设计模式-011:组合模式(Composite Pattern)
一:针对迭代器模式,当添加新菜单时不方便 class Waitress{ Menu pancakeHouseMenu; Menu dinnerMenu;
public Waitress(Menu pancakeHouseMenu, Menu dinnerMenu){ this.pancakeHouseMenu = pancakeHouseMenu; this.dinnerMenu = dinnerMenu; }
public string PrintMenu(){ StringBuilder sb = new StringBuilder();
Iterator pancakeIterator = pancakeHouseMenu.createIterator(); Iterator dinnerIterator = dinnerMenu.createIterator();
//不符合接口封闭原则 sb.Append("MENU/n----/nBREAKFAST/n"); sb.Append(PrintMenu(pancakeIterator)); sb.Append("/nLUNCH/n"); sb.Append(PrintMenu(dinnerIterator));
return sb.ToString(); }
public string PrintMenu(Iterator iterator){ StringBuilder sb = new StringBuilder(); while (iterator.hasNext()){ MenuItem menuItem = (MenuItem)iterator.next();
sb.Append(menuItem.getName + ", "); sb.Append(menuItem.getPrice + " -- "); sb.Append(menuItem.getDescription + "/n"); } return sb.ToString(); } }
static void Main(string[] args){ PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu(); DinerMenu dinerMenu = new DinerMenu(); CafeMenu cafeMenu = new CafeMenu();
Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu, cafeMenu); Console.WriteLine(waitress.PrintMenu()); }
二:组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象及对象组合。 为了保持透明性,组合内所有的对象必须实现相同的接口,否则客户就必须操心哪个对象调用哪个接口,这就失去了组合模式的意图。这也意味着有些对象具备一些没有意义的方法调用。 //菜单项不用分什么,作为统一的叶子节点 //需要维护菜单列表,列表项及菜单项
//将菜单和菜的选项全部放进来 public abstract class MenuComponent{ string name; string description; bool vegetarian; double price; public virtual string Name{ get {return name;} set {name = value;} } public virtual string Description{ get { return description; } set { description = value; } } public virtual bool IsVegetarian{ get { return vegetarian; } set { vegetarian = value; } } public virtual double Price{ get { return price; } set { price = value; } } public virtual void Add(MenuComponent menuComponent){ throw new UnsupportedOperationException(); } public virtual void Remove(MenuComponent menuComponent){ throw new UnsupportedOperationException(); } public virtual MenuComponent GetChild(int i) { throw new UnsupportedOperationException(); } public virtual string Print(){ throw new UnsupportedOperationException(); } public virtual ArrayList GetMenu(){ throw new UnsupportedOperationException(); } public virtual int Count(){ throw new UnsupportedOperationException(); } }
public class MenuItem : MenuComponent{ string name; string description; bool vegetarian; double price;
public MenuItem(string name, string description, bool vegetarian, double price){ this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } public override string Name{ get {return name;} set {this.name = value;} } public override string Description{ get{return description;} set{this.description = value;} } public override double Price{ get{return price;} set{price = value;} } public override bool IsVegetarian{ get{return vegetarian;} set{this.vegetarian = value;} } public override string Print(){ StringBuilder printOutPut = new StringBuilder(); printOutPut.Append("/t" + Name); if(IsVegetarian){ printOutPut.Append(" (v) "); } printOutPut.Append(", $" + Price + "/n"); printOutPut.Append("/t/t--" + Description +"/n");
return printOutPut.ToString(); } }
public class Menu : MenuComponent{ //关键 ArrayList menuComponents = new ArrayList(); string name; string description;
public Menu(string name, string description){ this.name = name; this.description = description; } public override string Name{ get {return name;} set {this.name = value;} } public override string Description{ get{return description;} set{this.description = value;} } //菜单中可以增加菜单项,但也可以增加菜单,所以要同一个父节点 public override void Add(MenuComponent menuComponent){ menuComponents.Add(menuComponent); } public override void Remove(MenuComponent menuComponent){ menuComponents.Remove(menuComponent); } public override MenuComponent GetChild(int i){ return (MenuComponent)menuComponents[i]; } public override ArrayList GetMenu(){ return menuComponents; } public override int Count(){ return menuComponents.Count; } public override string Print(){ StringBuilder printOutPut = new StringBuilder(); printOutPut.Append("/n" + name); printOutPut.Append(", " + description + "/n"); printOutPut.Append("-------------------------/n"); foreach(MenuComponent menuComponent in menuComponents){ printOutPut.Append(menuComponent.Print()); }
return printOutPut.ToString(); } }
public class Waitress{ MenuComponent allMenus; public Waitress(MenuComponent allMenus){ this.allMenus = allMenus; } public string PrintMenu(){ return allMenus.Print(); } public string PrintVegetarianMenu(){ StringBuilder printOutPut = new StringBuilder(); printOutPut.Append("/nVEGETARIAN MENU/n"); printOutPut.Append("-------------------------/n"); printOutPut.Append(GetChildMenuOutPutDown2Levels(allMenus.GetMenu())); return printOutPut.ToString(); } private string GetChildMenuOutPutDown2Levels(ArrayList menus){ StringBuilder printChildMenuOutPut = new StringBuilder();
foreach(MenuComponent menuComponent in menus){ for(int i = 0; i < menuComponent.Count(); i++){ if(menuComponent.GetChild(i).IsVegetarian){ printChildMenuOutPut.Append(menuComponent.GetChild(i).Print()); }
if(menuComponent.GetChild(i).GetType().Name == "Menu"){ for(int j = 0; j < menuComponent.GetChild(i).Count(); j++){ printChildMenuOutPut.Append(menuComponent.GetChild(i).GetChild(j).Print()); } } } } return printChildMenuOutPut.ToString(); } } //这样加菜单就非常方便了, static void Main(string[] args){ MenuComponent pancakeHouseMenu; pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU","Breakfast"); pancakeHouseMenu.Add(new MenuItem("1", "1", true, 2.99));
MenuComponent dinnerMenu; dinnerMenu = new Menu("DINNER MENU","Lunch"); dinnerMenu.Add(new MenuItem("2", "2", true, 2.99));
MenuComponent allMenus; allMenus.Add(pancakeHouseMenu); allMenus.Add(dinnerMenu);
Waitress waitress; waitress = new Waitress(allMenus); waitress.PrintMenu(); } //菜单中可以增加菜单项,但也可以增加菜单,所以要同一个父节点 public class MenuItem : MenuComponent public class Menu : MenuComponent
三:表明上看起来,上面MenuComponent多余 public class MenuItem{ string name; string description; bool vegetarian; double price;
public MenuItem(string name, string description, bool vegetarian, double price){ this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } public string Name{ get { return name; } set { this.name = value; } } public string Description{ get { return description; } set { this.description = value; } } public double Price{ get { return price; } set { price = value; } } public bool IsVegetarian{ get { return vegetarian; } set { this.vegetarian = value; } } } public class Menu{ ArrayList menuComponents = new ArrayList(); string name; string description;
public Menu(string name, string description){ this.name = name; this.description = description; } public string Name{ get { return name; } set { this.name = value; } } public string Description{ get { return description; } set { this.description = value; } }
public void Add(MenuItem menuComponent){ menuComponents.Add(menuComponent); }
public void Remove(MenuItem menuComponent){ menuComponents.Remove(menuComponent); }
public MenuItem GetChild(int i){ return (MenuItem)menuComponents[i]; }
public ArrayList GetMenu(){ return menuComponents; } public int Count(){ return menuComponents.Count; } } class Waitress{ Menu allMenus; public Waitress(Menu allMenus){ this.allMenus = allMenus; } } static void Main(string[] args) { Menu pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU", "Breakfast"); pancakeHouseMenu.Add(new MenuItem("1", "1", true, 2.99));
Menu dinnerMenu = new Menu("DINNER MENU", "Lunch"); dinnerMenu.Add(new MenuItem("2", "2", true, 2.99));
Menu allMenus; //如下代码,就通不过 //菜单作为节点,包含了很多菜单项 //但同时,菜单之间也可以作为父子节点, //所以才存在public class Menu : MenuComponent allMenus.Add(pancakeHouseMenu); allMenus.Add(dinnerMenu);
Waitress waitress; waitress = new Waitress(allMenus); }