重构IF ... ELSE desing

时间:2018-01-25 10:32:46

标签: c# design-patterns architecture

我有遗留代码和我的任务来重构它。

  1. 有基类(即车辆
  2. 它的继承人(汽车,公共汽车,摩托车等)
  3. 服务必须通过参数
  4. 选择并更新实例相应的继承人

    所以我有这样的事情:

    ...

       if (param == "car")
            result = new Car();
        else if (sectionType == "bus")
            result = new Bus();
        else if (sectionType == "motorcycle")
            result = new Motorcycle();
    

    ...

    我认为代码不具备生产力和支持

    问:我的目标是找到更好的设计解决方案。

    提前谢谢

1 个答案:

答案 0 :(得分:3)

你所拥有的是一个工厂,所以你可以将逻辑封装在工厂类中,以使其更清洁,更易于维护。

如果工厂类知道它需要创建的所有类型,那么它可以负责所有构造函数。但是,如果一个或多个车辆类未知,您可以为其提供某种注册方法,以便其他代码可以为其添加更多构造函数。

这是一个例子。让我们假设我们有:

public abstract class Vehicle {}
public class Car : Vehicle {}
public class Bus : Vehicle {}

然后你可以这样写一个工厂:

public sealed class VehicleFactory
{
    public VehicleFactory()
    {
        RegisterConstructor("car", () => new Car());
        RegisterConstructor("bus", () => new Bus());
    }

    public void RegisterConstructor(string name, Func<Vehicle> func)
    {
        _map.Add(name, func);
    }

    public Vehicle Create(string name)
    {
        if (_map.TryGetValue(name, out Func<Vehicle> create))
            return create();

        throw new InvalidOperationException($"No such vehicle name: {name}");
    }

    readonly Dictionary<string, Func<Vehicle>> _map = new Dictionary<string, Func<Vehicle>>();
}

现在假设您要支持工厂不了解的其他类型Motorcycle。您仍然可以通过让其他代码调用RegisterConstructor()来添加它来处理它,如下所示:

class Motorcycle : Vehicle { }

class Program
{
    static void Main()
    {
        var factory = new VehicleFactory();
        factory.RegisterConstructor("motorcycle", () => new Motorcycle());

        var bike = factory.Create("motorcycle");
        var car  = factory.Create("car");
    }
}

请注意,在实际代码中,您可能希望将具体类抽象为抽象基类或接口,但对于此示例,只使用具体类更简单。

另外,理想情况下,您希望通过VehicleFactory构造函数而不是使用RegisterConstructor()方法来使用依赖项注入:

public sealed class VehicleFactory
{
    public VehicleFactory(params (string name, Func<Vehicle> constructor)[] constructors)
    {
        _map.Add("car", () => new Car());
        _map.Add("bus", () => new Bus());

        foreach (var c in constructors)
        {
            _map.Add(c.name, c.constructor);
        }
    }

    public Vehicle Create(string name)
    {
        if (_map.TryGetValue(name, out Func<Vehicle> create))
            return create();

        throw new InvalidOperationException($"No such vehicle name: {name}");
    }

    readonly Dictionary<string, Func<Vehicle>> _map = new Dictionary<string, Func<Vehicle>>();
}

您可以这样使用:

class Motorcycle : Vehicle {}
class MilkFloat : Vehicle  {}

class Program
{
    static void Main()
    {
        var factory = new VehicleFactory(
            ("motorcycle", () => new Motorcycle()),
            ("milk float", () => new MilkFloat())
        );

        var bike = factory.Create("motorcycle");
        var car  = factory.Create("car");
        var milk = factory.Create("milk float");
    }
}