组合设计模式、迭代器设计模式

/*
菜单和菜单项

菜单
  |--陕菜
  	|--胡辣汤
  		|--肉丸胡辣汤
  		|--河南胡辣汤
  	|--羊肉泡馍
  		|--优质
  		|--普通
  		|--双份优质
  	|--三秦套餐	
  |--川菜
  	|--火锅
  	|--辣椒就朝天椒
  	|--伤心凉粉
  |--粤菜
  	|--鱼丸
  	|--虾丸
  	|--牛丸

*/
第一阶段:

package composite.a;

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

/*
	菜单和菜单项
	
	菜单
	  |--陕菜
	  	|--胡辣汤
	  		|--肉丸胡辣汤
	  		|--河南胡辣汤
	  	|--羊肉泡馍
	  		|--优质
	  		|--普通
	  		|--双份优质
	  	|--三秦套餐	
	  |--川菜
	  	|--火锅
	  	|--辣椒就朝天椒
	  	|--伤心凉粉
	  |--粤菜
	  	|--鱼丸
	  	|--虾丸
	  	|--牛丸
 */


class Menu{
	private String name;
	private String description;
	private List<MenuItem> list = new ArrayList<>();
	
	public Menu(String name, String description) {
		super();
		this.name = name;
		this.description = description;
	}

	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 void add(MenuItem mi) {
		list.add(mi);
	}
	
	public void print(String prefix) {
		System.out.println(prefix +"<<"+name+">>"+description);
		Iterator <MenuItem> it = list.iterator();
		while(it.hasNext()) {
			MenuItem mi = it.next();
			mi.print("\t"+prefix);
		}
	}
	
	
}
class MenuItem{
	private String name;
	private String description;
	
	
	
	public MenuItem(String name, String description) {
		super();
		this.name = name;
		this.description = description;
	}

	

	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 void print(String prefix) {
		System.out.println(prefix +name + ":"+description);
		
	}
	
}
public class AppTest {
	public static void main(String[] args) {
		Menu menu = new Menu("陕菜","老陕爱吃的菜");
		MenuItem mi = new MenuItem("鱼香肉丝","没有鱼 ");
		
		
		Menu menu2 = new Menu("胡辣汤","可以细分多种不同的胡辣汤");
		MenuItem mi2 = new MenuItem("a","aaa");
		MenuItem mi3 = new MenuItem("b","bbb");
		
		
		menu.add(mi);
		
		menu2.add(mi2);
		menu2.add(mi3);
		
		// Can't compile
		//因为现在的菜单只能添加菜单项。不能添加其他菜单
		//也就无法制作出多级菜单,也就是不能做出菜单的嵌套。
		//menu.add(menu2);
		
		menu.print("");
	}
}

第二阶段:
随手小记: 递归调用完成之后,回到其原来调用的地方
上述问题是:
1.菜单只能添加菜单项,不能添加菜单
2.不能出现嵌套的菜单形式
重构代码如下,要达到的目的:
1.菜单可以添加菜单和菜单项
2.菜单项不能再添加菜单项
就可以出现嵌套的菜单形式。
如下图所示:
在这里插入图片描述

package composite.b;

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


//菜单组件,用于提升菜单和菜单项的共性:
abstract class  MenuComponent{
	private String name;
	private String description;
	public MenuComponent(String name, String description) {
		super();
		this.name = name;
		this.description = description;
	}
	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 abstract void print(String prefix);
}

class Menu extends MenuComponent{
	
	private List<MenuComponent> list = new ArrayList<>();
	
	public Menu(String name, String description) {
		super(name,description);
	}

	
	//此时,add方法,就可以同时添加Menu和MenuItem了。
	public void add(MenuComponent mi) {
		list.add(mi);
	}
	
	public void print(String prefix) {
		System.out.println(prefix +"<<"+getName()+">>"+getDescription());
		Iterator <MenuComponent> it = list.iterator();
		while(it.hasNext()) {
			MenuComponent mi = it.next();
			mi.print("\t"+prefix);
		}
	}
	
	
}
class MenuItem extends MenuComponent{
	
	public MenuItem(String name, String description) {
		super(name,description);
	}
	
	public void print(String prefix) {
		System.out.println(prefix +getName() + ":"+getDescription());
		
	}
	
}
public class AppTest {
	public static void main(String[] args) {
		Menu menu = new Menu("蜗牛餐厅菜单","欢迎光临");
		Menu menu1 = new Menu("陕菜","xxxxxxx");
		Menu menu2 = new Menu("川菜","yyyyyy");
		Menu menu3 = new Menu("鲁菜","zzzzzz");
		
		MenuItem mi1 = new MenuItem("胡辣汤1" , "aaaaa");
		MenuItem mi2 = new MenuItem("胡辣汤2" , "aaaaa");
		MenuItem mi3 = new MenuItem("胡辣汤3" , "aaaaa");
		
		MenuItem mi4 = new MenuItem("剁椒鱼头1" , "aaaaa");
		MenuItem mi5 = new MenuItem("剁椒鱼头2" , "aaaaa");
		MenuItem mi6 = new MenuItem("剁椒鱼头3" , "aaaaa");
		
		MenuItem mi7 = new MenuItem("热干面1" , "aaaaa");
		MenuItem mi8 = new MenuItem("热干面2" , "aaaaa");
		MenuItem mi9 = new MenuItem("热干面3" , "aaaaa");
	
		menu.add(menu1);
		menu.add(menu2);
		menu.add(menu3);
		
		menu1.add(mi1);
		menu1.add(mi2);
		menu1.add(mi3);
		
		menu2.add(mi4);
		menu2.add(mi5);
		menu2.add(mi6);
		
		menu3.add(mi7);
		menu3.add(mi8);
		menu3.add(mi9);
		
		menu.print("");
	}
}
/*
 * 
 */

现在,蜗牛餐厅,改变了业务,因为有的客户端吃素,不吃肉。需要,有添加一个额外的功能,菜单中,只打印素食。

第三阶段:为了解决上面的问题:
1.客户需要素菜菜单
2.客户需要平价菜单
3.客户需要土豪菜单
4.客户需要辣菜菜单
重构代码如下:

package composite.c;

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

//菜单组件,用于提升菜单和菜单项的共性:
abstract class  MenuComponent{
	private String name;
	private String description;
	public MenuComponent(String name, String description) {
		super();
		this.name = name;
		this.description = description;
	}
	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 abstract void print(String prefix);
}

class Menu extends MenuComponent{
	
	private List<MenuComponent> list = new ArrayList<>();
	
	public Menu(String name, String description) {
		super(name,description);
	}

	
	//此时,add方法,就可以同时添加Menu和MenuItem了。
	public void add(MenuComponent mi) {
		list.add(mi);
	}
	
	public void print(String prefix) {
		System.out.println(prefix +"<<"+getName()+">>"+getDescription());
		Iterator <MenuComponent> it = list.iterator();
		while(it.hasNext()) {
			MenuComponent mi = it.next();
			mi.print("\t"+prefix);
		}
	}


	public List<MenuComponent> getList() {
		return list;
	}
	
	
	
	
	
}
class MenuItem extends MenuComponent{
	
	private boolean vegetarian;
	private double price;
	
	public MenuItem(String name, String description,boolean vegetarian,double price) {
		super(name,description);
		this.vegetarian = vegetarian;
		this.price = price;
	}
	
	public void print(String prefix) {
		String str = vegetarian? "(素食)":"";
		System.out.println(prefix +getName() + str+":"+getDescription());
	}

	public boolean isVegetarian() {
		return vegetarian;
	}

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





public class Test {
	
	//========================================
	public static void printV(Menu menu) {
		Iterator<MenuComponent> it = menu.getList().iterator();
		while(it.hasNext()) {
			MenuComponent mc = it.next();
			if(mc instanceof MenuItem) {
				if(((MenuItem) mc).isVegetarian()) {
					mc.print("");
				}
			}
			if(mc instanceof Menu) {
				printV((Menu)mc);
			}
		}
		
	}
	
	
	public static void main(String[] args) {
		Menu menu = new Menu("蜗牛餐厅菜单","欢迎光临");
		Menu menu1 = new Menu("陕菜","xxxxxxx");
		Menu menu2 = new Menu("川菜","yyyyyy");
		Menu menu3 = new Menu("鲁菜","zzzzzz");
		
		MenuItem mi1 = new MenuItem("胡辣汤1" , "aaaaa",false,6);
		MenuItem mi2 = new MenuItem("凉皮" , "aaaaa",true,6);
		MenuItem mi3 = new MenuItem("胡辣汤3" , "aaaaa",false,6);
		
		MenuItem mi4 = new MenuItem("剁椒鱼头1" , "aaaaa",false,12);
		MenuItem mi5 = new MenuItem("干煸豆角" , "aaaaa",true,12);
		MenuItem mi6 = new MenuItem("剁椒鱼头3" , "aaaaa",false,12);
		
		MenuItem mi7 = new MenuItem("牛肉拉面" , "aaaaa",false,9);
		MenuItem mi8 = new MenuItem("老干妈土豆丝" , "aaaaa",true,9);
		MenuItem mi9 = new MenuItem("热干面3" , "aaaaa",true,9);
	
		menu.add(menu1);
		menu.add(menu2);
		menu.add(menu3);
		
		menu1.add(mi1);
		menu1.add(mi2);
		menu1.add(mi3);
		
		menu2.add(mi4);
		menu2.add(mi5);
		menu2.add(mi6);
		
		menu3.add(mi7);
		menu3.add(mi8);
		menu3.add(mi9);
		
//		menu.print("");
		
		printV(menu);
		
		
	}
}



上述代码中出现的递归调用:
在这里插入图片描述

现在,很灵活,但是,客户端必须知道底层的数据结构。(迭代器模式)
另外一个缺点是,客户端必须知道MenuItem和Menu的存在。客户端应该只知道MenuCompunent的存在就足够了。(组合模式来解决)
第四阶段:为了解决c包中的问题,重构代码如下:

组合模式:将对象组合成树状结构,以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚“部分/整体”还有“单个对象”与“组合对象”的含义。

在这里,单个对象指的是菜单项;组合对象指的是菜单。

package composite.d;


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


//为了保证菜单和菜单项具有相同的接口,所以在他们的父类
//这里,把菜单需要的方法和菜单项需要的方法统统定义出来。
abstract class  MenuComponent{
	private String name;
	private String description;
	public MenuComponent(String name, String description) {
		super();
		this.name = name;
		this.description = description;
	}
	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 abstract void print(String prefix);
	
	//属于菜单的方法 : add remove getChild
	//这些方法对于菜单而言,是有意义的,但是对于菜单项而言没有意义。
	//那么为什么还要定义在这个父类中呢?
	//为的就是:组合模式中,使得用户对单个对象和组合对象的使用具有一致性。
	public void add(MenuComponent mc) {
		//抛出不支持的操作异常
		throw new UnsupportedOperationException();
	}
	public void remove(MenuComponent mc) {
		throw new UnsupportedOperationException();
	}
	public MenuComponent getChild(int i) {
		throw new UnsupportedOperationException();
	}
	//属于菜单项的方法:getPrice isVegetarian()
	//同样,对于菜单项而言,为了和组合对象的使用具有一致性。
	public double getPrice() {
		throw new UnsupportedOperationException();
	}
	public boolean isVegetarian() {
		throw new UnsupportedOperationException();
	}
	public  List<MenuComponent> getList(){
		throw new UnsupportedOperationException();
	};
	
	
}

class Menu extends MenuComponent{
	
	private List<MenuComponent> list = new ArrayList<>();
	
	public Menu(String name, String description) {
		super(name,description);
	}

	
	//此时,add方法,就可以同时添加Menu和MenuItem了。
	public void add(MenuComponent mc) {
		list.add(mc);
	}
	public void remove(MenuComponent mc) {
		list.remove(mc);
	}
	
	public MenuComponent getChild(int i) {
		return list.get(i);
	}
	
	public void print(String prefix) {
		System.out.println(prefix +"<<"+getName()+">>"+getDescription());
		Iterator <MenuComponent> it = list.iterator();
		while(it.hasNext()) {
			MenuComponent mi = it.next();
			mi.print("\t"+prefix);
		}
	}

	public List<MenuComponent> getList() {
		return list;
	}
	
	
	
	
	
}
class MenuItem extends MenuComponent{
	
	private boolean vegetarian;
	private double price;
	
	public MenuItem(String name, String description,boolean vegetarian,double price) {
		super(name,description);
		this.vegetarian = vegetarian;
		this.price = price;
	}
	
	public void print(String prefix) {
		String str = vegetarian? "(素食)":"";
		System.out.println(prefix +getName() + str+":"+getDescription());
	}

	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 class Test {
	
	//========================================
	public static void printV(MenuComponent me) {
		Iterator<MenuComponent> it = me.getList().iterator();
		while(it.hasNext()) {
			MenuComponent mc = it.next();
			
				try {
					if(mc.isVegetarian()) {
					mc.print("");
					}
				} catch (Exception e) {
					printV(mc);
				}
			}
			
		}
		
	
	
	
	public static void main(String[] args) {
		Menu menu = new Menu("蜗牛餐厅菜单","欢迎光临");
		Menu menu1 = new Menu("陕菜","xxxxxxx");
		Menu menu2 = new Menu("川菜","yyyyyy");
		Menu menu3 = new Menu("鲁菜","zzzzzz");
		
		MenuItem mi1 = new MenuItem("胡辣汤1" , "aaaaa",false,6);
		MenuItem mi2 = new MenuItem("凉皮" , "aaaaa",true,6);
		MenuItem mi3 = new MenuItem("胡辣汤3" , "aaaaa",false,6);
		
		MenuItem mi4 = new MenuItem("剁椒鱼头1" , "aaaaa",false,12);
		MenuItem mi5 = new MenuItem("干煸豆角" , "aaaaa",true,12);
		MenuItem mi6 = new MenuItem("剁椒鱼头3" , "aaaaa",false,12);
		
		MenuItem mi7 = new MenuItem("牛肉拉面" , "aaaaa",false,9);
		MenuItem mi8 = new MenuItem("老干妈土豆丝" , "aaaaa",true,9);
		MenuItem mi9 = new MenuItem("热干面3" , "aaaaa",true,9);
	
		menu.add(menu1);
		menu.add(menu2);
		menu.add(menu3);
		
		menu1.add(mi1);
		menu1.add(mi2);
		menu1.add(mi3);
		
		menu2.add(mi4);
		menu2.add(mi5);
		menu2.add(mi6);
		
		menu3.add(mi7);
		menu3.add(mi8);
		menu3.add(mi9);
		
//		menu.print("");
		
		printV(menu);
		
		
	}
}

第五阶段:此时客户端只依赖于MenuComponent,而不再知道Menu和MenuItem的存在了,这样符合了最少知道原则。
此时,仍然需要客户端自己写递归代码,这样对客户端不友好,最理想的情况是,hasNext , next

为了解决d包中的问题:
客户端需要自己写递归代码,重构代码如下:让客户端只需要调用hasNext 和next即可。

package composite.e;


import java.awt.Component;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;


//为了保证菜单和菜单项具有相同的接口,所以在他们的父类
//这里,把菜单需要的方法和菜单项需要的方法统统定义出来。
abstract class  MenuComponent{
	private String name;
	private String description;
	public MenuComponent(String name, String description) {
		super();
		this.name = name;
		this.description = description;
	}
	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 abstract void print(String prefix);
	
	//属于菜单的方法 : add remove getChild
	//这些方法对于菜单而言,是有意义的,但是对于菜单项而言没有意义。
	//那么为什么还要定义在这个父类中呢?
	//为的就是:组合模式中,使得用户对单个对象和组合对象的使用具有一致性。
	public void add(MenuComponent mc) {
		//抛出不支持的操作异常
		throw new UnsupportedOperationException();
	}
	public void remove(MenuComponent mc) {
		throw new UnsupportedOperationException();
	}
	public MenuComponent getChild(int i) {
		throw new UnsupportedOperationException();
	}
	//属于菜单项的方法:getPrice isVegetarian()
	//同样,对于菜单项而言,为了和组合对象的使用具有一致性。
	public double getPrice() {
		throw new UnsupportedOperationException();
	}
	public boolean isVegetarian() {
		throw new UnsupportedOperationException();
	}
	public  List<MenuComponent> getList(){
		throw new UnsupportedOperationException();
	};
	
	
}

class Menu extends MenuComponent{
	
	private List<MenuComponent> list = new ArrayList<>();
	
	public Menu(String name, String description) {
		super(name,description);
	}

	
	//此时,add方法,就可以同时添加Menu和MenuItem了。
	public void add(MenuComponent mc) {
		list.add(mc);
	}
	public void remove(MenuComponent mc) {
		list.remove(mc);
	}
	
	public MenuComponent getChild(int i) {
		return list.get(i);
	}
	
	public void print(String prefix) {
		System.out.println(prefix +"<<"+getName()+">>"+getDescription());
		Iterator <MenuComponent> it = list.iterator();
		while(it.hasNext()) {
			MenuComponent mi = it.next();
			mi.print("\t"+prefix);
		}
	}

	public List<MenuComponent> getList() {
		return list;
	}
	
	public CompositeIterator iterator() {
		return new CompositeIterator(list.iterator());
	}
	
	
	
	
	
}
class MenuItem extends MenuComponent{
	
	private boolean vegetarian;
	private double price;
	
	public MenuItem(String name, String description,boolean vegetarian,double price) {
		super(name,description);
		this.vegetarian = vegetarian;
		this.price = price;
	}
	
	public void print(String prefix) {
		String str = vegetarian? "(素食)":"";
		System.out.println(prefix +getName() + str+":"+getDescription());
	}

	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;
	}
}

class CompositeIterator implements Iterator<MenuComponent>{
	private Stack<Iterator<MenuComponent>> s = new Stack();
	public CompositeIterator (Iterator<MenuComponent> it) {
		s.push(it);
	}
	
	public boolean hasNext() {
		if(s.isEmpty()) {
			return false;
		}else {
			Iterator<MenuComponent> it = s.peek();
			if(!it.hasNext()) {
				s.pop();
				return hasNext();
			}else {
				return true;
			}
		}
	}
	@Override
	public MenuComponent next() {
		Iterator<MenuComponent> it = s.peek();
		MenuComponent mc = it.next();
		
		if(mc instanceof Menu) {
			s.push(((Menu)mc).getList().iterator());
		}
		return mc;
	}
	
}


public class Test {
	public static void main(String[] args) {
		Menu menu = new Menu("蜗牛餐厅菜单","欢迎光临");
		Menu menu1 = new Menu("陕菜","xxxxxxx");
		Menu menu2 = new Menu("川菜","yyyyyy");
		Menu menu3 = new Menu("鲁菜","zzzzzz");
		
		MenuItem mi1 = new MenuItem("胡辣汤1" , "aaaaa",false,6);
		MenuItem mi2 = new MenuItem("凉皮" , "aaaaa",true,6);
		MenuItem mi3 = new MenuItem("胡辣汤3" , "aaaaa",false,6);
		
		MenuItem mi4 = new MenuItem("剁椒鱼头1" , "aaaaa",false,12);
		MenuItem mi5 = new MenuItem("干煸豆角" , "aaaaa",true,12);
		MenuItem mi6 = new MenuItem("剁椒鱼头3" , "aaaaa",false,12);
		
		MenuItem mi7 = new MenuItem("牛肉拉面" , "aaaaa",false,9);
		MenuItem mi8 = new MenuItem("老干妈土豆丝" , "aaaaa",true,9);
		MenuItem mi9 = new MenuItem("热干面3" , "aaaaa",true,9);
	
		menu.add(menu1);
		menu.add(menu2);
		menu.add(menu3);
		
		menu1.add(mi1);
		menu1.add(mi2);
		menu1.add(mi3);
		
		menu2.add(mi4);
		menu2.add(mi5);
		menu2.add(mi6);
		
		menu3.add(mi7);
		menu3.add(mi8);
		menu3.add(mi9);
		

		
		CompositeIterator iterator = menu.iterator();
		while(iterator.hasNext()) {
			MenuComponent next = iterator.next();
			
			try {
				if(next.isVegetarian()) {
					System.out.println(next.getName()+"  "+next.getDescription());
				}
			} catch (Exception e) {
				//吞异常
			}
			
		}
			
	}
}




其中,表示迭代器模式的代码如下:

class CompositeIterator implements Iterator<MenuComponent>{
	private Stack<Iterator<MenuComponent>> s = new Stack();
	public CompositeIterator (Iterator<MenuComponent> it) {
		s.push(it);
	}
	
	public boolean hasNext() {
		if(s.isEmpty()) {
			return false;
		}else {
			Iterator<MenuComponent> it = s.peek();
			if(!it.hasNext()) {
				s.pop();
				return hasNext();
			}else {
				return true;
			}
		}
	}
	@Override
	public MenuComponent next() {
		Iterator<MenuComponent> it = s.peek();
		MenuComponent mc = it.next();
		
		if(mc instanceof Menu) {
			s.push(((Menu)mc).getList().iterator());
		}
		return mc;
	}
	
}


迭代器模式的解释:具体见设计模式-mr.gaoP75/P76
如图所示为迭代器设计模式的示意图
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值