模板模式(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();
}
}