Design patterns 是否有添加“的模式?”;选项“;去上课?
我有一个类,我想允许几个(~20+)配置选项。 每个选项打开或关闭一项功能,或以其他方式更改操作。 为了实现这一点,我用默认值编写了一个单独的选项类。然而,我不得不在代码中添加保护条件,以确定方法的行为方式。我几乎完成了,但现在代码似乎有味道 是否有一种首选方法/模式来实现这样的类Design patterns 是否有添加“的模式?”;选项“;去上课?,design-patterns,configuration,Design Patterns,Configuration,我有一个类,我想允许几个(~20+)配置选项。 每个选项打开或关闭一项功能,或以其他方式更改操作。 为了实现这一点,我用默认值编写了一个单独的选项类。然而,我不得不在代码中添加保护条件,以确定方法的行为方式。我几乎完成了,但现在代码似乎有味道 是否有一种首选方法/模式来实现这样的类 IdMap elementsById = (options.useIdAttribute) ? new IdMapImpl() : new NullIdMap(); public Element getElemen
IdMap elementsById = (options.useIdAttribute) ? new IdMapImpl() : new NullIdMap();
public Element getElementById(final string id) {
return elementsById.get(id);
}
编辑:更具体地说,我正在处理一个解析类。
每个选项配置基本解析算法的互斥部分。
例如,我班上有几个区域如下所示:
if (this.Option.UseIdAttribute)
attributeIDs = new Hashtable();
else
attributeIDs = null;
public Element GetElementById(string id)
{
if (string.IsNullOrEmpty (id))
throw new ArgumentNullException("id");
if (attributeIDs == null)
throw new Exception(ExceptionUseIdAttributeFalse);
return attributeIDs[id.ToLower()] as Element;
}
这辆车怎么样?它是为向类动态添加行为而设计的。我正在考虑一种模式
它看起来像:
public class MyClass {
interface Command {
void execute(int a);
}
static class DoThisSimpleCommand implements Command {
void execute(int a) {
// do this simple
}
}
static class DoThisAnotherWayCommand implements Command {
void execute(int a) {
// do this another way
}
}
private Command doThisCommand;
MyClass() {
initDoThisCommand();
}
private void initDoThisCommand() {
if (config.getDoThisMethod().equals("simple")) {
doThisCommand = new DoThisSimpleCommand();
} else {
doThisCommand = new DoThisAnotherWayCommand();
}
}
void doThis(int a) {
doThisCommand.execute(a);
}
}
换言之;您将责任委托给在构建时实例化的实现。现在,您的dot只是委托,而实际的功能完全隐藏在它自己的类中 确实存在另一种模式,称为builder模式,正是出于此目的。通常,当您有一个类,但每个“配置”选项可能都是可选的,可能只是在某些组合中。(,但这并不能准确描述我的情景) 您创建了两个类—要构建的类和生成器。builder类负责计算哪些选项组合是可选的,哪些组合有意义,等等 e、 例如,你想代表一种沙拉,但只有某些成分“味道好”,所以只有那些应该制作
Class Salad {
private Veggie v;
private Egg e;
private Meat m;
// etc etc, lots of properties
//constructor like this is nice
Salad(SaladBuilder builder) {
//query the builder to actually build the salad object.
//getVeggie() will either return the supplied value,
//or a default if none exists.
this.v = builder.getVeggie();
//rest of code omitted
}
//otherwise this constructor is fine, but needs a builder.build() method
Salad(Veggie v, Meat m, Egg e) { //code omitted
}
}
class SaladBuilder {
//some default, or left to null depending on what is needed
private Veggie v = SOME_DEFAULT_VEGGIE;
private Egg e;
private Meat m;
// etc etc, lots of properties.
//similar functions for each ingredient,
//or combination of ingredients that only make sense together
public SaladBuilder addIngredient(Meat m) {
this.m = m;
return this;
}
public SaladBuilder addIngredient(Veggie v) {
this.v = v;
return this;
}
public Salad build(){
// essentially, creates the salad object, but make sure optionals
// are taken care of here.
return new Salad(getBeggie(), getMeat(), getEgg());
}
}
用法示例
Salad s = new SaladBuilder().addIngredient(v).addIngredient(m).build();
对于打开/关闭功能的选项,我认为Decorator是@Thomas Owens所说的方式。我更关心改变函数的选项。如果无法链接这些操作,则许多装饰器将无法工作。例如,如果您的代码看起来像:
public void ActionABC()
{
if (options.DoA)
{
A();
}
if (options.DoB)
{
B();
}
if (options.DoC)
{
C();
}
}
public void ActionCAB()
{
if (options.DoC)
{
C();
}
if (options.DoA)
{
A();
}
if (options.DoB)
{
B();
}
}
这将很难用Decorator处理,因为每个动作方法的组合顺序不同
有20多个选项,假设它们是开/关的,您有400多个不同的可能组合。我怀疑并非所有这些组合的可能性都相同。对于无法通过Decorator处理的事情,您可能需要考虑映射到设置组合的操作模式。仅支持最受欢迎的模式。如果模式的数量很少,您可以通过子类化来处理这个问题,然后使用Decorators向表示用户选择的模式的子类添加功能。您可以使用工厂根据配置选择并构建适当的类
从本质上讲,我想我是说,你可能想考虑一下你是否需要和你正在建造的一样多的灵活性和随之而来的复杂性。考虑通过减少配置选项的数量,将它们分解成更小的更可能被使用的模式。
您打算如何执行相互依赖的选项的规则?如果您可以动态添加选项,那么如果您选择了命令模式,您可能会被迫拥有多个调用程序,或者您可能必须实现一个case语句来构建您需要执行的命令。
类似的东西怎么样IdMap elementsById = (options.useIdAttribute) ? new IdMapImpl() : new NullIdMap();
public Element getElementById(final string id) {
return elementsById.get(id);
}
基于以下类型:
interface IdMap {
Element get(String id);
}
class NullIdMap implements IdMap {
public Element get(final String id) {
throw new Exception(/* Error message */);
}
}
class IdMapImpl implements IdMap {
Map<String, Element> elements = new HashMap<String, Element>();
public Element get(final String id) {
rejectEmpty(id);
return elements.get(id.toLowerCase());
}
}
接口IdMap{
元素get(字符串id);
}
类NullIdMap实现IdMap{
公共元素get(最终字符串id){
抛出新异常(/*错误消息*/);
}
}
类IdMapImpl实现IdMap{
Map elements=newhashmap();
公共元素get(最终字符串id){
拒绝为空(id);
返回元素.get(id.toLowerCase());
}
}
在这里,我们使用该模式来处理禁用useIdAttribute的特殊情况。当然有一个折衷办法——解析器类本身更具表现力,而现在有4种类型而不是1种。对于get方法来说,这种重构似乎有些过分,但是当您添加一个“put()”方法等时,它的好处是将“特殊情况”逻辑定位在单个类(NullIdMap)中
[rejectEmpty是一个帮助器方法,如果传递的是空字符串,则会引发异常。]使用类似策略或策略模式的方法在这里可能会很有用。这是一种很好的方法,可以根据运行时某些特定数据的配置或(不)存在来封装或交换算法的不同实现 在您的场景中,如果您的解析类通常具有相同类型的行为(输入或输出),但内部算法发生了变化,那么您可能希望基于它来实现
我考虑过这一点,但我会再次检查代码,看看它是否合适。起初我认为这有点过分,我想避免类膨胀。装饰器模式也是我的答案。您不必以与GoF书籍或Headfirst设计模式完全相同的方式使用它——模式不是配方。根据您的需要调整它。除非您发布代码,否则很难说……这个示例是用Java而不是C#编写的,但它仍然很有启发性。20+布尔选项超过一百万个组合,不是吗?