1.场景问题解决
1.1 场景描述
还是餐厅,多个餐厅合并,每个餐厅的菜单实现方式不一样,有的为ArrayList有的为Array.
1.2 OO设计
参见:10迭代器模式
1.3 需求变动
增加餐后甜点子菜单,需要改子菜单和原菜单列表中的菜单项同级.
原菜单列表中都为MenuItem,而现在还要增加子菜单.
要求如下:
[外链图片转存失败(img-ALTDnFFQ-1566140566608)(https://raw.githubusercontent.com/bobshute/public/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/11%E7%BB%84%E5%90%88%E6%A8%A1%E5%BC%8F-1%E5%AD%90%E8%8F%9C%E5%8D%95.png)]
1.4 带来问题
2.用设计模式改进
可以让菜单和子菜单继承某一个超类,该超类有自己的迭代器.
2.1 分析
2.2 重新设计
[外链图片转存失败(img-wHut5p25-1566140566609)(https://raw.githubusercontent.com/bobshute/public/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/11%E7%BB%84%E5%90%88%E6%A8%A1%E5%BC%8F-2%E7%B1%BB%E5%9B%BE.png)]
2.3 源码
- MenuComponent(抽象接口类)
- MenuItem(主菜单),SubMenu(子菜单)
public abstract class MenuComponent {
public String getName() {
return "";
}
public String getDescription() {
return "";
}
public float getPrice() {
return 0;
}
public boolean isVegetable() {
return false;
}
public abstract void print();
public Iterator getIterator() {
return new NullIterator();
}
}
public class MenuItem extends MenuComponent {
private String name,description;
private boolean vegetable;
private float price;
public MenuItem(String name,String description,boolean vegetable,float price)
{
this.name=name;
this.description=description;
this.vegetable=vegetable;
this.price=price;
}
@Override
public String getName()
{
return name;
}
@Override
public String getDescription()
{
return description;
}
@Override
public float getPrice()
{
return price;
}
@Override
public boolean isVegetable()
{
return vegetable;
}
@Override
public void print() {
System.out.println(getName() + "***" + getPrice() + "***"
+ getDescription());
}
}
public class SubMenu extends MenuComponent {
private ArrayList<MenuComponent> menuItems;
public SubMenu() {
menuItems = new ArrayList<MenuComponent>();
addItem("Apple Cookie", "Apple&candy&Cookie", true, 1.99f);
addItem("Banana Cookie", "Banana&candy&Cookie", false, 1.59f);
addItem("Orange Cookie", "Orange&Cookie", true, 1.29f);
}
private void addItem(String name, String description, boolean vegetable,
float price) {
MenuItem menuItem = new MenuItem(name, description, vegetable, price);
menuItems.add(menuItem);
}
public Iterator getIterator() {
return new ComposeIterator(menuItems.iterator());
}
@Override
public void print() {
System.out.println("****This is SubMenu****");
}
}
- ComposeIterator 组合迭代器
- NullIterator 空迭代器
public class ComposeIterator implements Iterator {
private Stack<Iterator> stack = new Stack<Iterator>();
public ComposeIterator(Iterator iterator) {
stack.push(iterator);
}
@Override
public boolean hasNext() {
if (stack.empty()) {
return false;
}
Iterator iterator = stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
} else {
return true;
}
}
@Override
public Object next() {
if (hasNext()) {
Iterator iterator = stack.peek();
MenuComponent mMenuComponent = (MenuComponent) iterator.next();
stack.push(mMenuComponent.getIterator());
return mMenuComponent;
}
return null;
}
@Override
public void remove() {
}
}
public class NullIterator implements Iterator{
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
return null;
}
@Override
public void remove() {
}
}
- CakeHouseMenu 蛋糕店(不包含子菜单)
- DinerMenu 小餐厅(包含子菜单)
public class CakeHouseMenu extends MenuComponent {
private ArrayList<MenuComponent> menuItems;
public CakeHouseMenu() {
menuItems = new ArrayList<MenuComponent>();
addItem("KFC Cake Breakfast", "boiled eggs&toast&cabbage", true, 3.99f);
addItem("MDL Cake Breakfast", "fried eggs&toast", false, 3.59f);
addItem("Stawberry Cake", "fresh stawberry", true, 3.29f);
addItem("Regular Cake Breakfast", "toast&sausage", true, 2.59f);
}
private void addItem(String name, String description, boolean vegetable,
float price) {
MenuItem menuItem = new MenuItem(name, description, vegetable, price);
menuItems.add(menuItem);
}
public Iterator getIterator() {
return new ComposeIterator(menuItems.iterator());
}
@Override
public void print() {
System.out.println("****This is CakeHouseMenu****");
}
}
public class DinerMenu extends MenuComponent {
private final static int Max_Items = 5;
private int numberOfItems = 0;
private MenuComponent[] menuItems;
public DinerMenu() {
menuItems = new MenuComponent[Max_Items];
addItem("vegetable Blt", "bacon&lettuce&tomato&cabbage", true, 3.58f);
addItem("Blt", "bacon&lettuce&tomato", false, 3.00f);
addItem("bean soup", "bean&potato salad", true, 3.28f);
addItem("hotdog", "onions&cheese&bread", false, 3.05f);
addSubMenu(new SubMenu());
}
private void addItem(String name, String description, boolean vegetable,
float price) {
MenuItem menuItem = new MenuItem(name, description, vegetable, price);
if (numberOfItems >= Max_Items) {
System.err.println("sorry,menu is full!can not add another item");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
}
private void addSubMenu(MenuComponent mMenuComponent) {
if (numberOfItems >= Max_Items) {
System.err.println("sorry,menu is full!can not add another item");
} else {
menuItems[numberOfItems] = mMenuComponent;
numberOfItems++;
}
}
public Iterator getIterator() {
return new ComposeIterator(new DinerIterator());
}
class DinerIterator implements Iterator {
private int position;
public DinerIterator() {
position = 0;
}
@Override
public boolean hasNext() {
if (position < numberOfItems) {
return true;
}
return false;
}
@Override
public Object next() {
MenuComponent menuItem = menuItems[position];
position++;
return menuItem;
}
@Override
public void remove() {
}
}
@Override
public void print() {
System.out.println("****This is DinerMenu****");
}
}
- MenuControl菜单控制器
- ComposeTest 测试类
public class MenuControl {
private ArrayList<MenuComponent> iterators = new ArrayList<MenuComponent>();
public MenuControl() {
}
public void addComponent(MenuComponent mMenuComponent) {
iterators.add(mMenuComponent);
}
//打印所有菜单
public void printMenu() {
Iterator iterator;
MenuComponent menuItem;
for (int i = 0, len = iterators.size(); i < len; i++) {
iterators.get(i).print();
iterator = iterators.get(i).getIterator();
while (iterator.hasNext()) {
menuItem = (MenuComponent) iterator.next();
menuItem.print();
}
}
}
public void printBreakfastMenu() {
}
public void printLunchMenu() {
}
public void printVegetableMenu() {
Iterator iterator;
MenuComponent menuItem;
for (int i = 0, len = iterators.size(); i < len; i++) {
iterators.get(i).print();
iterator = iterators.get(i).getIterator();
while (iterator.hasNext()) {
menuItem = (MenuComponent) iterator.next();
if (menuItem.isVegetable()) {
menuItem.print();
}
}
}
}
}
public class ComposeTest {
public static void main(String[] args) {
MenuControl mMenuControl = new MenuControl();
CakeHouseMenu mCakeHouseMenu = new CakeHouseMenu();
DinerMenu mDinerMenu = new DinerMenu();
//打印主菜单
mMenuControl.addComponent(mCakeHouseMenu);
//打印主菜单及子菜单
mMenuControl.addComponent(mDinerMenu);
//打印主/子菜单中的特定产品(素食)
mMenuControl.printVegetableMenu();
}
}
3.设计模式总结
3.1 定义
*** 组合模式:*** 将对象聚合成树形结构来表现“整体/部分”的层次结构。
组合模式能让客户以一致的方式来处理个别对象以及对象组合。也就是我们可以忽略对象组合与个体对象之间的差别
3.2 分析思路
- 新增一个菜单超类(超类中有一个默认迭代器NullIterator);菜单超类对应一个超类迭代器;菜单超类和菜单超类迭代器来处理数据;
- 普通菜单和子菜单都继承菜单超类
- 普通菜单(CakeHouseMenu)继承菜单超类不重写Iterator(用默认的NullIterator)
- 包含子菜单(DinerMenu)继承超类后重写Iterator(内部有自己的迭代器).
4. 设计模式使用场景及注意
5.参考文章
内容总计于HeadFirst设计模式及相关视频