7

In my factory method I use Switch statement to create concrete objects. This results in very high cyclomatic complexity. Here is a sample code:

private static UnitDescriptor createUnitDescriptor(string code)
{
     switch (code)
     {
         case UnitCode.DEG_C:
             return new UnitDescriptorDegC();

         case UnitCode.DEG_F:
             return new UnitDescriptorDegF();

         :
         :
         default:
             throw new SystemException(string.format("unknown code: {o}", code);
      }
  }

How can I refactor this to reduce cyclomatic complexity? If I use reflection to create objects or something else to build objects is it better than above method?

4

2 回答 2

9

您可以使用 a完全Dictionary删除该switch语句:

class MyClass
{
    private static Dictionary<string, Func<UnitDescriptor>> dict = new Dictionary<string, Func<UnitDescriptor>>();

    static MyClass()
    {
        dict.Add(UnitCode.DEG_C, () => new UnitDescriptorDegC());
        dict.Add(UnitCode.DEG_F, () => new UnitDescriptorDegF());
        // Other mappings...
    }

    private static UnitDescriptor createUnitDescriptor(string code)
    {
        Func<UnitDescriptor> value;
        if (dict.TryGetValue(code, out value))
        {
            return value();
        }

        throw new SystemException(string.Format("unknown code: {0}", code));
    }
}
于 2013-08-23T08:51:00.480 回答
0

这个问题是谷歌搜索“圈复杂度工厂”时的第一个结果。字典的使用大大降低了圈复杂度,但是正如 PHP 中的 niconoe 所指出的那样,使用这种方法会增加内存使用量,因为对象是在运行时加载的。

为了解决这个问题,我们可以使用 Dictionary + Closures。闭包内声明的对象在调用闭包之前不会创建。

class NotTriggered
{

    public function __construct()
    {
        echo "not triggered\n";
    }

    public function trigger()
    {
        echo "still not triggered\n";
    }

}

class triggered
{

    public function __construct()
    {
        echo "triggered\n";
    }

    public function trigger()
    {
        echo "triggered again\n";
    }

}

function echoHello()
{
    echo "hello\n";
}

function echoWorld()
{
    echo "world\n";
}

$arr = [
    0 => fn() => echoHello(),
    1 => echoWorld(),
    2 => fn() => (new NotTriggered)->trigger(),
    3 => (new Triggered)->trigger(),
];

//output :
//world
//triggered
//triggered again

所以在工厂方法中,代码可能看起来像这样

public function createService($serviceName): ServiceInterface
{
    $services = [
        'service1' => fn() => new Service1(),
        'service2' => fn() => new Service2(),
        'service3' => fn() => new Service3(),
    ];

    return $services[$serviceName] ?? throw new \Exception('service not registered');
}
于 2021-08-13T15:05:31.797 回答