如何在函数调用中强制执行序列
假设我想设计一个客户端需要以特定顺序调用函数的类,例如,
hasNext(); next();
或者,作为一个非常通用的例子,一个类CookFood
与方法:
class CookFood { getListOfItems(); mixAllItems(); heat(); }
在第二个例子中,我想强制说,只有在获得物品后才能进行混合,并且只有在混合后才能进行加热。 是否有任何已知的模式或良好实践强制执行函数调用序列?
您可能对Step Builder Pattern感兴趣。 它并不一定适合您所呈现的所有情况,但其想法是每个操作都会返回一些实现接口的东西,以便您执行下一个操作。 由于您只能通过以正确的顺序执行操作来获取对象,因此您将被迫以正确的顺序执行它们。
虽然在迭代(next / hasNext)情况下会感觉有点强迫,但你可以想象它
- 穿上你的袜子,
- 然后穿上你的鞋子
模式。 不知何故,你得到了一个CanWearSocks
接口的实例,它只有以下方法。
CanWearShoes putOnSocks()
当你调用putOnSocks()
,你得到你的CanWearShoes
实例,它只有以下方法。
SockAndShoeWearer putOnShoes()
当你打电话给putOnShoes()
你现在有穿袜子和鞋子的东西,你被迫以正确的顺序进行。
特别好的是,你可以在两种情况下实际使用相同的对象,但由于方法签名只返回接口类型,代码只能使用接口方法(除非代码是偷偷摸摸的,并将对象转换为不同类型)。
例
这是一个实现迭代模式的相当人为的例子,即确保在NextGetter之前使用NextChecker。
public class StepBuilderIteration { interface NextChecker { NextGetter hasNext(); } interface NextGetter { Object next(); NextChecker more(); } static class ArrayExample { final static Integer[] ints = new Integer[] { 1, 2, 3, 4 }; public static NextChecker iterate() { return iterate( 0 ); } private static NextChecker iterate( final int i ) { return new NextChecker() { public NextGetter hasNext() { if ( i < ints.length ) { return new NextGetter() { public Object next() { return ints[i]; } public NextChecker more() { return iterate( i+1 ); } }; } else { return null; } } }; } } public static void main(String[] args) { NextChecker nc = ArrayExample.iterate(); while (nc != null) { NextGetter ng = nc.hasNext(); if (ng != null) { System.out.println(ng.next()); nc = ng.more(); } } } }
输出是:
1 2 3 4
如果您可以完全访问源代码并且可以对其进行修改,那么是什么阻止您使用工厂方法模式与模板方法模式的组合。 一个简单的例子:
public class CookFood { public Food MakeFood() { PrepareFood(); HeatFood(); ServeFood(); } protected abstract void PrepareFood(); protected abstract void HeatFood(); protected abstract ServeFood(); }
现在,代码的客户可以调用MakeFood
,它将强制执行步骤顺序,如果您想自定义任何步骤,那么您可以将CookFood
子类CookFood
并实现该特定步骤。 当然, PrepareFood(), HeatFood(), ServeFood()
不一定是抽象的,您可以使用默认实现,您可以在子类中重写以进行自定义。
执行所需操作的一种方法是在调用函数时设置标志,然后在调用从属函数时检查是否设置了该标志。
例如:
public void getListOfItems() { funcGetListOfItemsCalled = true; .... } public void mixAllItems() { if(funcGetListOfItemsCalled) { funcMixAllItemsCalled = true; ... } } public void mixAllItems() { if(funcMixAllItemsCalled ) { ... } }
可以有不同的方法,其中一种列在这里。 虽然这种方法认为在调用另一个函数之前需要调用另一个函数但不总是。 您可以根据需要进行编辑:
-
创建变量以检查函数调用的状态。 每当有人调用listOfItems时,您可以将isListed变量设置为true。 然后检查mixAllItems中isListed的值,以确保先前调用了getListOfItems。
class CookFood { boolean isListed; boolean isMixed; boolean isHeated; public String getListOfItems() { // do listing and mark as listed isListed = true; return "something"; } public void mixAllItems() { // check if listed first if (isListed) { // do mixing // mark as mixed isMixed = true; } else { System.out.println("You need to call getListOfItems before mixing"); return; } } public void heat() { if (isMixed) { // do heating // mark as mixed isHeated = true; } else { System.out.println("You need to call isMixed before heating"); return; } } }