软件设计模式-模板模式-迭代器模式

本文探讨了软件设计中的两种模式:模板模式和迭代器模式。模板模式用于优化相似算法流程,通过抽象模板函数实现代码复用,并允许子类动态扩展。而迭代器模式则是在不关心具体集合实现的情况下,提供统一的遍历接口,以兼容不同类型的集合,并降低代码改动成本。文中提供了示例代码以说明这两种模式的用法。
摘要由CSDN通过智能技术生成

模板模式(Template Model)

当某些事物有着相似的算法流程的时候 我们就可以使用模板模式优化冗余代码

例如咖啡和茶的烹饪 他们的算法流程是基本一致 变的只不过是一些配料

示例代码如下

import java.util.Scanner;

/**  
* @Title: TemplateModelTest.java  
* @Package   
* @Description: TODO(用一句话描述该文件做什么)  
* @author Lustre  
* @date 2019年12月11日  
* @version V1.0  
*/
/**
* @author Nigel
* @version 创建文件时间:2019年12月11日 下午12:57:55
*/

/**
 * 
* @ClassName: CaffeineBeverage  
* @Description: 这里我们将这个算法模板抽象了出来 然后在子类中实现这个算法模板 这样可以极大量的避免算法的一个冗余 
* @author Nigel  
* @date 2019年12月11日  
*
 */
abstract class CaffeineBeverage {
	public void prepareRecipe() {
		//煮沸
		boilWater();
		//冲泡
		brew();
		//倒进杯子
		pourInCup();
		//加配料
		if ( customAddingCondiment() ) {
			addCondiment();
		}
		
	}
	
	protected void boilWater() {
		System.out.println("boiling water....");
	}
	
	protected void pourInCup() {
		System.out.println("pour into cup...");
	}
	
	/**
	 * 
	* @Title: customAddingCondiment  
	* @Description: 选择是否自制的加入自己的配料 我们可以通过用户的输入选择是否加入配料 子类可以覆盖我们称为"Hook"的一个方法 然后由子类进行扩展
	* @return void    
	* @throws
	 */
	protected Boolean customAddingCondiment() {
		//在超类中我们只需要默认选择true即可 然后子类选择性的去覆盖重写该方法
		return true;
	}
	
	abstract protected void brew();
	abstract protected void addCondiment();
	
}

class Tea extends CaffeineBeverage {

	@Override
	protected void brew() {
		// TODO Auto-generated method stub
		System.out.println("steeping the tea...");
	}

	@Override
	protected void addCondiment() {
		// TODO Auto-generated method stub
		System.out.println("Adding lemon...");
	}
	
	/**
	 * 
	* <p>Title: customAddingCondiment</p>  
	* <p>Description: 例如我们现在去复写这个钩子 我们可以获取用户输入 然后用户输入yes 我们会加lemon 不然我们不加
	* @return  
	* @see CaffeineBeverage#customAddingCondiment()
	 */
	@Override
	protected Boolean customAddingCondiment() {
		// 在子类实现我们自己的钩子函数
		Scanner inputScanner = new Scanner(System.in);
		System.out.print("Do you want to add some lemon into your tea? Input your answer : ");
		String userInputString = inputScanner.next();
		if (userInputString.toLowerCase().startsWith("yes")) {
			return true;
		} 
		return false;
	}
	
	
}

class Coffee extends CaffeineBeverage {

	@Override
	protected void brew() {
		// TODO Auto-generated method stub
		System.out.println("brew the coffee...");
	}

	@Override
	protected void addCondiment() {
		// TODO Auto-generated method stub
		System.out.println("Adding sugar and some milk...");
	}
	
}

/**  
* @ClassName: TemplateModelTest  
* @Description: TODO(这里用一句话描述这个类的作用)  
* @author Nigel  
* @date 2019年12月11日  
*    
*/
public class TemplateModelTest {

	/**  
	* @Title: main  
	* @Description: TODO  
	* @param args    
	* @return void    
	* @throws
	*/
	public static void main(String[] args) {
		// 测试咖啡和茶的冲泡
		// 测试咖啡的冲泡
		System.out.println("测试咖啡的冲泡:");
		CaffeineBeverage myCoffee = new Coffee();
		myCoffee.prepareRecipe();
		// 测试茶的冲泡
		System.out.println("测试茶的冲泡:");
		CaffeineBeverage myTea = new Tea();
		myTea.prepareRecipe();
	}
}

使用模板方法 我们可以轻易的实现算法级别的代码复用 并且可以在模板函数中根据我们以后可能有的变化 动态的对算法流程加上钩子函数(Hook) 然后由子类去根据实际需求进行动态的扩展

迭代器模式(Iterator Model)

试想这样一种情况 当我们想要整合两个用了不同实现的集合 例如一个程序使用ArrayList 一个程序使用数组 我们现在想要最大化的减少对原先代码的变动 而又能准确无误的用最少的代码遍历这两个不同的集合 并且最后能后续兼容其他用了不同实现的集合 并且整合的时候我们是应该不知道这两个他们的实现是怎样的 即我们应该只获得一个能遍历的接口即可 而不需要整合程序再去搞清楚它的实现 在我们的这个例子中 我们遇到的变化是遍历 所以我们抽象出一个共同的接口 即Iterator

示例代码如下

import java.util.ArrayList;

/**  
* @Title: IteratorModelTest.java  
* @Package   
* @Description: TODO(用一句话描述该文件做什么)  
* @author Lustre  
* @date 2019年12月11日  
* @version V1.0  
*/
/**
* @author Nigel
* @version 创建文件时间:2019年12月11日 下午7:50:17
*/


class MenuItem {
	String name;
	String description;
	Boolean vegetarian;
	Double price;
	 
	 
	public MenuItem(String name, String description, Boolean vegetarian, Double price) {
		this.name = name;
		this.description = description;
		this.vegetarian = vegetarian;
		this.price = price;
	}
	
	public String getName() {
		return name;
	}
	public String getDescription() {
		return description;
	}
	public Boolean getVegetarian() {
		return vegetarian;
	}
	public Double getPrice() {
		return price;
	}
	 
	 
}

 /**
  * 
 * @ClassName: Iterator  
 * @Description: 我们封装的就是遍历的变化 我们将它封装到这个接口中 只需要两个参数 一个是检测是否到底 一个是取出下一个元素
 * @author Nigel  
 * @date 2019年12月11日  
 *
  */
interface Iterator {
	Boolean hasNext();
	MenuItem next();
}

class PancakeMenuIterator implements Iterator {
	private Integer currentPosition;//维护一个指针 用于能在遍历时找到当前位置
	private ArrayList<MenuItem> menuList;
	/**  
	* 创建一个新的实例 PancakeMenuIterator.  
	*    
	*/
	public PancakeMenuIterator(ArrayList<MenuItem> menuList) {
		this.menuList = menuList;
		currentPosition = 0;
	}
	
	/**
	* <p>Title: hasNext</p>  
	* <p>Description: </p>  
	* @return  
	* @see Iterator#hasNext()  
	*/  
	@Override
	public Boolean hasNext() {
		return ( (currentPosition < menuList.size()) && (menuList.get(currentPosition) != null) );
	}

	/**
	* <p>Title: next</p>  
	* <p>Description: </p>  
	* @return  
	* @see Iterator#next()  
	*/  
	@Override
	public MenuItem next() {
		// 获得当前元素 并且
		return menuList.get(currentPosition++);
	}
	
}

class DinerIterator implements Iterator {
	private Integer currentPosition;//维护一个指针 用于能在遍历时找到当前位置
	private MenuItem[] menuList;
	/**  
	* 创建一个新的实例 PancakeMenuIterator.  
	*    
	*/
	public DinerIterator(MenuItem[] menuList) {
		this.menuList = menuList;
		currentPosition = 0;
	}
	
	/**
	* <p>Title: hasNext</p>  
	* <p>Description: </p>  
	* @return  
	* @see Iterator#hasNext()  
	*/  
	@Override
	public Boolean hasNext() {
		return ( (currentPosition < menuList.length) && (menuList[currentPosition] != null) );
	}

	/**
	* <p>Title: next</p>  
	* <p>Description: </p>  
	* @return  
	* @see Iterator#next()  
	*/  
	@Override
	public MenuItem next() {
		// 获得当前元素 并且
		return menuList[currentPosition++];
	}
	
}

interface Menu {
	Iterator createMenuIterator();
}

/**
 * 
* @ClassName: PancakeHouseMenu  
* @Description: 这里我们实现了这个迭代器接口 这样的话我们最后得到的就是一个迭代器 这里使用ArrayList的方法
* @author Nigel  
* @date 2019年12月11日  
*
 */
class PancakeHouseMenu implements Menu{	 
	private ArrayList<MenuItem> menuList;
	
	/**  
	* 创建一个新的实例 PancakeHouseMenu.  
	*    
	*/
	public PancakeHouseMenu() {
		menuList = new ArrayList<MenuItem>();//初始化菜单
		//添加对应的菜单
		addMenuItem("Pancake", "pancake is delicious", true, 2.99);
		addMenuItem("蓝莓蛋糕	", "蛋糕夹着鸡蛋和香肠", false, 2.99);
		addMenuItem("煎饼操作", "煎饼早餐~", false, 3.49);
	}
	
	/**
	 * 
	* @Title: getPancakeHouseMenu  
	* @Description: 当需要获取菜单的时候 就返回一个迭代器回去
	* @return    
	* @return Iterator    
	* @throws
	 */
	@Override
	public Iterator createMenuIterator() {
		return new PancakeMenuIterator(menuList);
	}
	
	/**
	 * 
	* @Title: addMenuItem  
	* @Description: 这是个工具函数 用于本身的使用
	* @param name
	* @param description
	* @param vegetarian
	* @param price
	* @return    
	* @return MenuItem    
	* @throws
	 */
	private void addMenuItem(String name, String description, Boolean vegetarian, Double price) {
		menuList.add(new MenuItem(name, description, vegetarian, price));
	}

	
}
 
class DinerMenu implements Menu{
	private Integer currentPosition = 0; 
	private static final int MAX_ITEMS = 3;
	private MenuItem[] menuArray;
	
	/**  
	* 创建一个新的实例 DinerMenu.  
	*    
	*/
	public DinerMenu() {
		// 初始化数组
		menuArray = new MenuItem[MAX_ITEMS];
		addItem("培根+土豆", "BLT", false, 2.99);
		addItem("Vegetarian BLT", "Bacon with lettuce & tomato", true, 3.09);
		addItem("Soup Of The Day", "with a slide of potato salad", false, 3.29);
	}
	
	private void addItem(String name, String description, Boolean vegetarian, Double price) {
		if (currentPosition >= MAX_ITEMS) {
			System.out.println("The menu is full, NO ADDING INTO THE MENU!");
			return;
		}
		menuArray[currentPosition++] = new MenuItem(name, description, vegetarian, price);
	}
	
	@Override
	public Iterator createMenuIterator() {
		return new DinerIterator(menuArray);
	}
	
}


/**
 * 
* @ClassName: Stewardess  
* @Description: 服务员根据顾客选择的菜单 显示出菜单的详细信息
* @author Nigel  
* @date 2019年12月11日  
*
 */
class Stewardess {
	 //这里使用组合方式 获得两种迭代器接口 这样我们不需要关心其内部究竟用什么存储 我们只需要通过这个迭代器接口就可以进行遍历获取全部的菜单项信息
	private Iterator menuIterator;
	
	/**  
	* 创建一个新的实例 Stewardess.  传入一个Object 即Menu 由于这里没有使用多态 所以没法传参
	*    
	*/
	public Stewardess(Menu menu) {
		menuIterator = menu.createMenuIterator();
	}
	
	public void printMenu() {
		while (menuIterator.hasNext()) {
			MenuItem menuItem = (MenuItem) menuIterator.next();
			printMenuItem(menuItem);
		}
	}
	
	/**
	 * 
	* @Title: printMenu  
	* @Description: 将菜单打印封装成一个工具方法
	* @param menuItem    
	* @return void    
	* @throws
	 */
	private void printMenuItem(MenuItem menuItem) {
		System.out.println("------" + menuItem.getName() + "------");
		System.out.println("Description:" + menuItem.getDescription());
		System.out.println("Vegetarian:" + menuItem.getVegetarian());
		System.out.println("Price:" + menuItem.getPrice());
	}
}
 
 
 
 /**  
 * @ClassName: IteratorModelTest  
 * @Description: TODO(这里用一句话描述这个类的作用)  
 * @author Nigel  
 * @date 2019年12月11日  
 *    
 */
public class IteratorModelTest {

	/**  
	* @Title: main  
	* @Description: TODO  
	* @param args    
	* @return void    
	* @throws
	*/
	public static void main(String[] args) {
		// 测试
		System.out.println("测试PancakeMenu:");
		//选择一个menu
		Menu pancakeMenu = new PancakeHouseMenu();
		Stewardess myStewardess = new Stewardess(pancakeMenu);
		myStewardess.printMenu();
		System.out.println("测试DinerMenu:");
		Menu dinerMenu = new DinerMenu();
		myStewardess = new Stewardess(dinerMenu);
		myStewardess.printMenu();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值