C#设计模式 - 如何根据高度可配置的用户选择编写代码

时间:2009-11-22 17:47:24

标签: c# design-patterns

我想编写没有很多开关的代码,if / else,以及其他基于用户输入执行逻辑的典型语句。

例如,假设我有一个我要组装的Car类并调用Car.Run()。更重要的是,让我们说轮胎我可以根据用户输入选择4种不同的轮胎类别。

对于,我不知道,身体类型,让我说我有10个体​​型类可供选择来构建我的汽车对象,依此类推。

使用可配置参数的数量将此示例放大1000时使用的最佳模式是什么。

是否有这种模式?我看过工厂和抽象的工厂模式,他们不太适合这个,虽然看起来应该这样。

7 个答案:

答案 0 :(得分:5)

我不认为工厂模式会在这里失职。我就是这样设置的。我没有看到你如何摆脱基于switch / if的逻辑,从根本上说,你的用户正在做出选择。

public class Car {
   public Engine { get; set; }
   //more properties here
}

public class EngineFactory {
  public Engine CreateEngine(EngineType type {
     switch (type) {
        case Big:
           return new BigEngine();
        case Small:
           return new SmallEngine();
     }
  }   
}

public class Engine {

}

public class BigEngine : Engine {

}

public class SmallEngine : Engine {

}

public class CarCreator {
   public _engineFactory = new EngineFactory();
   //more factories

   public Car Create() {
    Car car = new Car();

    car.Engine = _engineFactory.CreateEngine(ddlEngineType.SelectedValue);
    //more setup to follow

    return car;
   }
}

答案 1 :(得分:3)

您告诉的问题可以使用Dependency Injection解决。

有很多框架实现了这种模式(例如,对于.NET - 优秀的Castle.Windsor容器)。

答案 2 :(得分:1)

我认为elder_george是正确的:你应该查看DI容器。但是,您可能需要检查builder pattern (here too),它通过组合多个部分来处理“构建”复杂对象。如果有的话,这可能会为你提供一些灵感,而且听起来比工厂更接近你的问题。

答案 3 :(得分:1)

如果您在工厂中引入注册逻辑,您可以绕过必须使用大量if或switch语句,注册条目会在您的工厂中为您的字典添加绑定:

Dictionary<Type,Func<Engine>> _knownEngines;

在上面的行中,您将类型绑定到工厂函数,例如:

private void RegisterEngine<TEngineType>(Func<T> factoryFunc) where TEngineType : Engine
{
    _knownEngines.Add(typeof(TEngineType), factoryFunc);
}

这将允许您致电:

RegisterEngine<BigEngine>(() => new BigEngine()); 

在您的工厂

所以现在你有办法让你的工厂知道大量的引擎,而不需要求助于if / switch语句。如果你的所有引擎都有一个无参数构造函数,你甚至可以将上面的内容改进为:

public void RegisterEngine<TEngineType>() where TEngineType : Engine, new()
{
    _knownEngines.Add(typeof(TEngineType), () => new TEngineType());
}

这将允许您注册工厂可以创建的引擎:

RegisterEngine<BigEngine>();

现在我们只需要一种将用户输入与正确类型相关联的方法。 如果我们有某种枚举,我们可能想要将枚举值映射到它们对应的类型。有许多方法可以实现这一点,或者以与我们已经完成的方式类似的方式使用字典,但这次它是作为键的枚举和作为值的类型,或者通过使用相应的类型{{来装饰枚举值。 3}}(如果你有很多值,这种可能性很有意思)

但是,我们可以跳过这一切,只需要一个快捷方式,直接将枚举与工厂函数关联起来。

所以我们会让我们的字典看起来像这样:

Dictionary<MyEngineEnumeration,Func<Engine>> _knownEngines;

您将注册引擎

public void RegisterEngine<TEngineType>(MyEngineEnumeration key) where TEngineType : Engine, new()
{
    _knownEngines.Add(key, () => new TEngineType());
}
像这样:     RegisterEngine(MyEngineEnumeration.BigEngine);

然后你会在你的工厂类中使用某种创建方法,它将你的枚举值作为关键:

public Engine ResolveEngine(MyEngineEnumeration key)
{
    // some extra safety checks can go here
    return _knownEngines[key]
}

所以你的代码会设置你的

Car.Engine = EngineFactory.ResolveEngine((MyEngineEnumeration)ddlEngine.SelectedValue)

您可以使用相同的花纹图案,依此类推。

根据您的要求,遵循注册/解决方法将允许您在xml文件或数据库中外部配置可用引擎,并允许您在不修改发布代码文件的情况下使更多引擎可用,但是通过部署新引擎装配这是一个有趣的前景。

祝你好运!

答案 4 :(得分:0)

您可以使用以下内容:

  1. 定义一个表示一组选项中的选项的类,即。一个TireType类,BodyType类。

  2. 为每个选项创建一个类的实例,从商店获取数据。填写一个集合,即TireTypeCollection。

  3. 使用该集合填充您向用户显示的任何控件,以便他选择选项,这样用户就可以选择实际选择的选项类。

  4. 使用选定的主题来构建课程。

  5. 如果任何功能需要行为中的chnge,您可以使用lamdas来表示该功能并序列化代码的表示以将其保存到存储中;或者您可以使用委托,为每个功能创建方法并选择正确的方法并将其保存到对象创建的委托中。

    我认为在这种方法中重要的是向用户提供的任何选项都是完全正常的,而不仅仅是名称或ID列表。

答案 5 :(得分:0)

您可以在C ++中尝试使用策略类技术。

http://beta.boost.org/community/generic_programming.html#policy

答案 6 :(得分:0)

您是否只是在询问是否可以基于字符串(或者甚至是Type对象)创建类的实例? 您可以使用Activator.CreateInstance

Type wheelType = Type.GetType("Namespace.WheelType");
Wheel w = Activator.CreateInstance(wheelType) as Wheel;

你可能想要检查最后创建的类,但这是另一个故事。