How to prevent Factory Method pattern causing warning about virtual member call in constructor?
在www.dofactory.com上,我找到了工厂模式的真实例子。但代码在resharper中生成一个关于构造函数中虚拟成员调用的警告。
导致警告的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | abstract class Document { private List<Page> _pages = new List<Page>(); // Constructor calls abstract Factory method public Document() { this.CreatePages(); // <= this line is causing the warning } public List<Page> Pages { get { return _pages; } } // Factory Method public abstract void CreatePages(); } class Resume : Document { // Factory Method implementation public override void CreatePages() { Pages.Add(new SkillsPage()); Pages.Add(new EducationPage()); Pages.Add(new ExperiencePage()); } } |
在消费代码中,您可以简单地使用:
1 |
我确实理解为什么在构造函数中调用虚拟成员是一个坏主意(如这里所解释的)。
我的问题是,如何重构这一点,以便仍然使用工厂模式,但不需要在构造函数中调用虚拟成员。
如果我只是从构造函数中移除对
1 2 |
我更喜欢这样的情况,即创建一个新的
重构的一种方法是预先传递页面,然后将它们传递给受保护的构造函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public abstract class Document { protected Document(IEnumerable<Page> pages) { // If it's OK to add to _pages, do not use AsReadOnly _pages = pages.ToList().AsReadOnly(); } // ... } public class Resume : Document { public Resume() : base(CreatePages()) { } private static IEnumerable<Page> CreatePages() { return new Page[] { new SkillsPage(), new EducationPage(), new ExperiencePage() }; } } |
另外,我不知道这和工厂方法有什么关系。您的文章说明了模板方法模式。
My question is how you can refactor this in order to still use the factory pattern, but without the virtual member call in the constructor.
根据定义
In class-based programming, the factory method pattern is a creational pattern which uses factory methods to deal with the problem of creating objects without specifying the exact class of object that will be created.
工厂方法不打算从构造函数中使用,因为将创建的对象的确切类在构造时是已知的。例如,
如果
但如果
I much more prefer the situation where creating a new Resume is all that's needed to actually create a Resume containing pages.
因此,如果所有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class Document private readonly PageList as IList(of IPage) public readonly property Pages as IEnumerable(of IPage) get return PageList end get end property public sub new() Me.PageList = new List(of IPage) end sub protected sub Add(paramarray Pages() as IPage) Me.Pages.AddRange(Pages) end sub end public public class Resume inherits Document public sub new() mybase.add(new SkillsPage, new EducationPage, new ExperiencePage) end sub end class |
方法
方法
这个怎么样?它使用惰性初始化,只在需要时创建页面(而不是在构造函数中创建页面)。
另外,请注意,工厂方法可见性更改为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | abstract class Document{ protected List<Page> _pages = new List<Page>(); // Constructor calls abstract Factory method public Document(){} public List<Page> Pages { get { CreatePages(); return _pages; } } // Factory Method protected abstract void CreatePages(); } class Resume : Document{ // Factory Method implementation protected override void CreatePages(){ if(pages.Count == 0 ){ _pages .Add(new SkillsPage()); _pages .Add(new EducationPage()); _pages .Add(new ExperiencePage()); } } } |
编辑建议:我个人不喜欢使用全局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | abstract class Document{ public IEnumerable<Page> Pages{ get { return CreatePages();} } // Factory Method protected abstract IEnumerable<Page> CreatePages(); } class Resume : Document{ // Factory Method implementation protected override IEnumerable<Page> CreatePages(){ List<Page> _pages = new List<Page>(); _pages .Add(new SkillsPage()); _pages .Add(new EducationPage()); _pages .Add(new ExperiencePage()); return _pages; } } } |
您可以在属性本身中进行。
在这种情况下,可以在基类中将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
在这种情况下,页面将在首次访问