恭喜你,你发现了策略模式的一个缺点:
策略模式可用于托管没有参数或每个算法的参数集相同的不同算法。但是,如果要使用具有不同参数集的各种算法,则不足之处。
幸运的是,本文提出了一个优雅的解决方案:
将其应用于您的特定情况:
public abstract class ClerkResolver { // Role: Algorithm
protected Parameter[] parameters;
public Parameter[] getParameters() {
return parameters.clone();
}
abstract String resolveClerk();
}
class CountryClerkResolver extends ClerkResolver {
public CountryClerkResolver() {
parameters = new Parameter[1];
parameters[0] = new StringParameter("country", "Denmark"); // Default value is 'Denmark'
}
private String country;
@Override
String resolveClerk() {
country = ((StringParameter) parameters[0]).getValue();
// CountryClerkResolver specific code
return country;
}
}
class DefaultClerkResolver extends ClerkResolver { // Role: ConcreteAlgorithm
public DefaultClerkResolver() {
parameters = new Parameter[1];
parameters[0] = new StringParameter("department", "someName");
}
private String department;
@Override
public String resolveClerk() {
department = ((StringParameter) parameters[0]).getValue();
// DefaultClerkResolver specific code
return department;
}
}
public abstract class Parameter { // Role: Parameter
private String name;
public String getName() {
return name;
}
public Parameter(String name) {
this.name = name;
}
}
public class StringParameter extends Parameter { // Role: ConcreteParameter
private String value;
public StringParameter(String name, String value) {
super(name);
this.value = value;
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
使用示例:
public class Main {
public static void main(String... args) { // Role: client
ClerkResolver clerk_1 = new CountryClerkResolver();
Parameter[] parameters = clerk_1.getParameters();
StringParameter country = (StringParameter) parameters[0]; // [¤]
country.setValue("USA"); // Overwriting default value
clerk_1.resolveClerk();
}
}
如果您希望CountryClerkResolver
采用例如三个参数(其中一个是整数),您会这样做:
首先介绍一个 .IntegerParameter
public class IntegerParameter extends Parameter {
private int value;
public IntegerParameter(String name, int value) {
super(name);
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
现在改变策略的构造函数和方法:
class CountryClerkResolver extends ClerkResolver {
public CountryClerkResolver() {
parameters = new Parameter[1];
parameters[0] = new StringParameter( "country", "Denmark" ); // Default value is 'Denmark'
parameters[1] = new StringParameter( "newStringParam", "defaultVal");
parameters[2] = new IntegerParameter("newIntegerParam", 9999 );
}
private String country;
private String newStringParam;
private int newIntegerParam;
@Override
String resolveClerk() {
country = ((StringParameter) parameters[0]).getValue();
newStringParam = ((StringParameter) parameters[1]).getValue();
newIntegerParam = ((IntegerParameter) parameters[2]).getValue();
// CountryClerkResolver specific code
return country;
}
}
有关该模式的更详细说明,请参阅本文。
好处:
- [灵活]每当要添加新的混凝土或 .
Algorithm
Parameter
- 您不必处理算法(策略)的公共方法的签名,因为它不需要任何参数;参数将在调用方法之前进行 sat。
负债:
- [稳定性]在获取参数时(请参阅),程序员可能会混淆数组的索引。(例如,如果不是,但是,比如说,
[¤]
parameters
parameters[0]
country
continent
)
-
- 解决稳定性问题的可能解决方案是,尽管以可分析性为代价:
public class Main {
public static void main(String... args) { // Role: client
ClerkResolver clerk_1 = new CountryClerkResolver();
Parameter[] parameters = clerk_1.getParameters();
// Analyzability suffers because of ugly casting:
StringParameter country = (StringParameter) getParameterWithName("country", parameters);
country.setValue("USA"); // Overwriting default value
clerk_1.resolveClerk();
}
private static Parameter getParameterWithName(String paramName, Parameter[] parameters) {
for (Parameter param : parameters)
if (param.getName().equals(paramName))
return param;
throw new RuntimeException();
}
}
-
-
- 为了提高可读性,可以引入 的抽象:
Parameter[]
import java.util.ArrayList;
import java.util.List;
public class ParameterList {
private final List<Parameter> parameters;
public ParameterList(int length) {
this.parameters = new ArrayList<>(length);
}
public void add(Parameter p) {
parameters.add(p);
}
private Parameter getParameterOf(String name) {
return parameters.stream()
.filter(p -> p.getName().equals(name))
.findFirst()
.orElse(null);
}
// =================================================== ~~~~~~~~~~~~~~~~~~~~~~~~
// The liability of ParameterList is that we have to write a lot of boilerplate getter methods.
// However, because most parameter to any strategy class is a primitive type (or String), we don't
// have to continiously add new methods; this is thus acceptable.
// === A getter for each type of {@code Parameter} is needed ~~~~~~~~~~~~~~~~~~~~~~~~
public StringParameter getStringParameterOf(String name) {
return (StringParameter) getParameterOf(name);
}
public IntegerParameter getIntegerParameterOf(String name) {
return (IntegerParameter) getParameterOf(name);
}
// === A value of each type of {@code Parameter} is needed ~~~~~~~~~~~~~~~~~~~~~~~~
public String getValueOfStringParameter(String name) {
return ((StringParameter) getParameterOf(name)).getValue();
}
public int getValueOfIntegerParameter(String name) {
return ((IntegerParameter) getParameterOf(name)).getValue();
}
// =================================================== ~~~~~~~~~~~~~~~~~~~~~~~~
public ParameterList clone() throws CloneNotSupportedException {
return (ParameterList) super.clone();
}
}
GitHub:所有代码