静态Create方法-与构造函数相比的优缺点


11

在构造函数上使用静态对象创建方法的利弊是什么?

class Foo {
  private Foo(object arg) { }

  public static Foo Create(object arg) {
    if (!ValidateParam(arg)) { return null; }
    return new Foo(arg);
  }
}

我能想到的很少:

优点:

  • 返回null而不是引发异常(将其命名为TryCreate)。这可以使客户端的代码更简洁明了。客户很少期望构造函数失败。
  • 创建具有清晰语义的不同种类的对象,例如CreatFromName(String name)CreateFromCsvLine(String csvLine)
  • 必要时可以返回缓存的对象或派生的实现。

缺点:

  • 较少发现,更难以浏览代码。
  • 某些模式(例如序列化或反射)更加困难(例如Activator<Foo>.CreateInstance()

1
慢一点 无论如何,您都必须处理空引用。
阿米尔·雷扎伊

1
@Amir处理null为(Foo x = Foo.TryCreate(); if (x == null) { ... })。处理ctor异常为(Foo x; try { x = new Foo(); } catch (SomeException e) { ... })。当调用普通方法时,我更喜欢异常而不是错误代码,但是在创建对象时,它TryCreate看起来更干净。
dbkk 2010年

您会在验证中进行任何类型检查吗?
阿米尔·雷扎伊

关于第二个Pro,“使用清晰的语义创建不同种类的对象,例如CreatFromName(String name)和CreateFromCsvLine(String csvLine)”,创建NameCsvLine键入可能会更好,而不是通过方法名称来表达需求。这将允许您重载Create。对这两者使用字符串可能被认为是“原始痴迷”(假设出于已知的性能原因尚未做出此选择)。查看对象健美操,以有趣的方式探索这一点。
bentayloruk

Answers:


7

静态“ 创建者 ” 的最大缺点可能是限制了继承。如果您或您的图书馆用户从中派生了一个类Foo,那么Foo::Create()它将变得毫无用处。在那里定义的所有逻辑都必须在继承的中再次重写Create()

我建议采取一种折衷方案:用一个永不失败/抛出的简单对象初始化逻辑定义一个构造函数,然后用缓存,替代构造等方法定义创建者。这使得派生的可能性成为可能,并且您可以受益于给定类的创建者。


1
实际上,这并不是真正的问题,因为大多数类并非设计为继承自(因此应该是密封的/最终的)。如果后来发现您想打开继承的类,则始终可以将任何初始化逻辑移至受保护的构造函数。
2013年

7

创建是工厂方法。当我觉得有需要时,我实现了Factory模式,并定义了一个接口来表示用于创建对象的契约以及一个实现类,然后在需要时将其注入。这保留了将创建责任移出类的优点,但是避免了(或至少更加明显地)了在类构造函数之外执行对象创建的限制。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.