我有一个基类Base
,它需要创建另一种类型的实例TRequired
,但是,只有派生类Base
知道如何构造它们。
使用抽象属性作为工厂方法是不好的风格吗?例如
protected abstract TRequired NewTRequired { get; }
我应该出于某种原因使用一种方法吗?是否有指南为什么我应该/不应该在这里使用属性?
我有一个基类Base
,它需要创建另一种类型的实例TRequired
,但是,只有派生类Base
知道如何构造它们。
使用抽象属性作为工厂方法是不好的风格吗?例如
protected abstract TRequired NewTRequired { get; }
我应该出于某种原因使用一种方法吗?是否有指南为什么我应该/不应该在这里使用属性?
你绝对应该使用一个方法,因为访问这个成员会做一些事情。调用方法是让代码在这方面自己说话的好方法。
或者,如果您更喜欢另一种观点:成员的两次后续访问将返回不同的结果。一个好的经验法则是在这种情况下使用一种方法,以免违反最小惊讶原则。
这看起来像是在读取变量的结果,即使您知道这NewTRequired
是一个属性(而不是字段),您也知道实际上它正在运行任意代码:
var prototype = Factory.NewTRequired;
我特意将结果放入一个名为的变量prototype
中,以便更好地表明即使是了解此代码的知情读者也很容易被抛弃:看到这一点并认为“正确,NewTRequired
X 的原型对象也是如此”并不是不合理的。 . 那位读者肯定会对这样的代码结果感到惊讶:
var eq = object.ReferenceEquals(prototype, Factory.NewTRequired);
将此与工厂方法进行对比。现在这段代码可能会散发出轻微的气味:
// hmmm... are we actually using this as a prototype?
// because it sure looks like an instance created just for the occasion.
var prototype = Factory.NewTRequired();
这段代码永远不会让你感到惊讶:
// obviously should be false, the code screams "I am creating new instances!"
var eq = object.ReferenceEquals(Factory.NewTRequired(), Factory.NewTRequired());
一个真正应该遵循但没有遵循这条规则的著名例子是DateTime.Now
财产。
我会推荐一种方法:
protected abstract TRequired CreateRequired();
创造意味着“工作”的发生。这更适合方法与属性,因为属性 getter 意味着通常无需执行太多代码即可快速返回的内容。
甚至您的问题标题“作为工厂方法的属性”也暗示工厂方法应该是方法。
属性是为“看起来像”字段的事物设计的,例如对象的位置。
每次获得它时都返回一个新实例的属性是非常糟糕的设计。
您应该改用一种方法。