假设我想设计一个客户端需要以特定顺序调用函数的类,例如,
hasNext();
next();
或者,作为一个非常通用的示例,类CookFood
包含方法:
class CookFood {
getListOfItems();
mixAllItems();
heat();
}
在第二个例子中,我想强制说只有在获得物品后才能进行混合,并且只有在混合后才能进行加热。是否存在强制执行函数调用序列的已知模式或良好实践?
答案 0 :(得分:30)
您可能对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
答案 1 :(得分:5)
如果您拥有对源代码的完全访问权限并且可以对其进行修改,那么是什么阻止您使用Factory Method模式与Template Method模式的组合。一个简单的例子:
public class CookFood {
public Food MakeFood() {
PrepareFood();
HeatFood();
ServeFood();
}
protected abstract void PrepareFood();
protected abstract void HeatFood();
protected abstract ServeFood();
}
现在,代码的客户端可以调用MakeFood
来强制执行步骤顺序,如果要自定义任何步骤,则可以继承CookFood
并实现该特定步骤。当然步骤PrepareFood(), HeatFood(), ServeFood()
不一定是抽象的,你可以有一个默认的实现,你可以在子类中覆盖它来进行自定义。
答案 2 :(得分:0)
可以有不同的方法,其中一种列在这里。虽然这种方法认为你需要在调用另一个函数之前调用另一个函数,但并不总是如此。您可以根据需要进行编辑:
创建变量以检查函数调用的状态。每当有人调用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;
}
}
}
答案 3 :(得分:0)
执行所需操作的一种方法是在调用函数时设置标志,然后检查在调用相关函数时是否设置了该标志。
例如:
public void getListOfItems() {
funcGetListOfItemsCalled = true;
....
}
public void mixAllItems() {
if(funcGetListOfItemsCalled) {
funcMixAllItemsCalled = true;
...
}
}
public void mixAllItems() {
if(funcMixAllItemsCalled ) {
...
}
}