How to prevent Factory method template causing a warning about calling a virtual member in the constructor?

On www.dofactory.com I found a real Factory template example. But the code generates a warning in ReSharper about calling the virtual member in the constructor.

The warning code is as follows:

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()); } } 

In the consumption code, you can simply use:

 Document document = new Resume(); 

I understand why it is a bad idea to call a virtual member in the constructor (as explained here ).

My question is how can you reorganize this to use the Factory pattern, but without invoking the virtual member in the constructor.

If I just deleted the CreatePages call from the constructor, the consumer would have to explicitly call the CreatePages method:

 Document document = new Resume(); document.CreatePages(); 

I like the situation much more when creating a new Resume is all that is needed to create pages containing resumes.

+8
c # design-patterns factory-method
source share
4 answers

One way to refactor is to forward pages forward and pass them to the protected constructor:

 public abstract class Document { protected Document(IEnumerable<Page> pages) { // If it 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() }; } } 

PS I'm not sure if this is due to the factory method. Your message illustrates the Template Method Template .

+2
source share

How about this? It uses lazy initialization, where pages are created only when necessary (instead of creating them in the constructor)

Also note that the visibility of the factory method has been changed to protected in order to hide it from public use.

 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()); } } } 

EDIT Suggestion: I personally donโ€™t like having this global variable _pages , as it can cause you problems if it is used in conjunction with many methods and threads. I would rather use the factory method template as described in the GoF book. Here is my suggestion:

 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
source share

My question is how can you reorganize this to use the factory template, but without calling the virtual member in the constructor.

By definition

In class-based programming, the factory method template is a creation template that uses factory methods to solve the problem of creating objects without specifying the exact class of the object to be created.

The factory method is not intended to be used by the constructor, since the exact class of the object to be created is known at build time. For example,

  • if the Document must create all Pages at build time, then it can do it without the factory method, since it knows exactly all the pages that will be created

  • but if Document should create Pages later after building, and possibly several times, then factory is useful

I prefer the situation when creating a new resume is all that is needed to create pages containing resumes.

So, if all Pages must be created at build time, this specific example can be rewritten without using the factory method template:

 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 
  • The Add method is allowed for use from the Resume constructor, since the Document object is fully constructed and ready for use.

  • The Add method is protected, so pages can only be added from Document or derived classes.

+1
source share

You can do it in yourself.

In this case, the Pages property can be marked as virtual in the base class.

Mortgage code for Resume might look like this:

  private List<Page> _pages = null; public override List<Page> Pages { get { if(pages == null) { _pages = new List<Page>(); _pages .Add(new SkillsPage()); _pages .Add(new EducationPage()); _pages .Add(new ExperiencePage()); } return _pages; } } } 

In this case, the pages will be created the first time you access the Pages property, and not when ctor executed.

0
source share

All Articles