我正在处理一个小pinball-game project的业余爱好,我正在寻找一种封装常量变量的模式。
我有一个模型,其中有一些值在该模型的生命周期内是恒定的,例如最大速度/最大重力等。在整个GUI和其他区域中,为了正确验证输入,需要这些值。目前,它们既可以作为public static final
的引用,也可以只是简单的硬编码。我想将这些“常量变量”封装在一个对象中,该对象可以注入到模型中,并由视图/控制器检索。
为了澄清,“常量变量”的值可能不一定在编译时定义,它们可能来自读取文件;用户输入等。在编译时已知的是需要的。一种可能更容易解释的方法是,无论这种封装是什么,它提供的值都是不可变的。
我正在寻找实现这一目标的方法:
我知道我可以定义一个具有以下方法的接口:
public int getMaximumSpeed();
public int getMaximumGravity();
...并将其实例注入模型,并以某种方式使其可访问。然而,这导致了大量的样板代码,这对编写/测试等非常繁琐(我这样做是为了测试: - ))。
我正在寻找一种更好的方法来做到这一点,最好是具有成为共享词汇的一部分的好处,就像设计模式一样。
有更好的方法吗?
P.S。我已经想到了更多关于这一点,我能找到的最好的权衡就是:
public class Variables {
enum Variable {
MaxSpeed(100),
MaxGravity(10)
Variable(Object variableValue) {
// assign value to field, provide getter etc.
}
}
public Object getVariable(Variable v) { // look up enum and get member }
} // end of MyVariables
然后我可以做类似的事情:
Model m = new Model(new Variables());
优点:变量的查找受到必须是枚举的成员的保护,以便编译,变量可以添加少量额外的代码
缺点:枚举不能扩展,脆弱(需要重新编译才能添加变量),变量值必须从Object(在本例中为Integer)中转换,这也不是类型安全的虽然泛型可能是一种选择...不知何故
答案 0 :(得分:2)
您是在寻找Singleton还是变种Monostate?如果没有,那么这种模式如何不能满足您的需求呢?
当然,这是强制性免责声明Anything Global Is Evil。
更新:我做了一些寻找,因为我一直有类似的辩论/问题。我偶然发现了list经典全球/范围解决方案的“替代方案”。以为我会分享。
答案 1 :(得分:1)
感谢你们花费的所有时间来破译这个非常奇怪的问题。
我认为,就设计模式而言,最接近我所描述的是工厂模式,我有一个伪常量工厂。从技术上讲,它不是每次调用都创建一个实例,而是始终提供相同的实例(在Guice提供者的意义上)。但我可以创建几个工厂,每个工厂都可以提供不同的伪常量,并将每个工厂注入不同的模型,因此模型的UI可以更灵活地验证输入。
如果有人感兴趣我得出的结论是,为每个psuedo-constant提供方法的接口是要走的路:
public interface IVariableProvider {
public int maxGravity();
public int maxSpeed();
// and everything else...
}
public class VariableProvider {
private final int maxGravity, maxSpeed...;
public VariableProvider(int maxGravity, int maxSpeed) {
// assign final fields
}
}
然后我可以做:
Model firstModel = new Model(new VariableProvider(2, 10));
Model secondModel = new Model(new VariableProvider(10, 100));
我认为只要接口不提供过多的变量getter,它就会胜过某些参数化查找(在运行时会很容易受到攻击,或者会禁止扩展/多态)。
P.S。我意识到有些人质疑我的问题是静态最终值。我向一位同事发表声明(用舌头的脸),任何静态的东西本身都不是面向对象的。因此,在我的爱好中,我使用它作为思考练习的基础,我尝试从项目中删除任何静态(接下来我将尝试删除所有'if'语句;-D)。如果我在截止日期前并且我满意公共静态最终值不会进行腿筋测试,我会很快使用它们。
答案 2 :(得分:0)
如果你只是使用java / IOC,为什么不只是依赖注入值?
e.g。 Spring通过map注入值,将对象指定为单例 -
<property name="values">
<map>
<entry> <key><value>a1</value></key><value>b1</value></entry>
<entry> <key><value>a2</value></key><value>b3</value></entry>
</map>
</property>
你的类是一个单例,它在spring中保存地图集的不可变副本 -
private Map<String, String> m;
public String getValue(String s)
{
return m.containsKey(s)?m.get(s):null;
}
public void setValues(Map m)
{
this.m=Collections.unmodifiableMap(m):
}
答案 3 :(得分:0)
据我所知,你可能不需要在这里实现一个模式 - 你只需要访问一组常量,在我看来,通过使用可公开访问的静态接口可以很好地处理给他们。除非我错过了什么。 :)
如果您只是想通过某种原因对“常量”进行“客体化”,那么可能需要使用Singleton模式,如果有的话;我知道你在评论中提到你不介意创建这个包装器对象的多个实例,但作为回应我会问,那么为什么甚至会引入因多个实例而产生的那种混乱?您正在寻找具有对象形式的数据满意度的实际好处吗?
现在,如果值不是常量,那就不同了 - 在这种情况下,您可能需要Singleton或Monostate。但如果它们确实是常量,只需在类中包装一组枚举或静态常量即可完成!保持简单就像任何一种“模式”一样好。