深入浅出设计模式-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);
}