C# 如何防止工厂方法模式导致构造函数中虚拟成员调用的警告?
在上,我发现了一个真实的工厂模式示例。但是代码在ReSharper中生成了一个关于构造函数中的虚拟成员调用的警告 引起警告的代码如下所示:C# 如何防止工厂方法模式导致构造函数中虚拟成员调用的警告?,c#,design-patterns,factory-method,C#,Design Patterns,Factory Method,在上,我发现了一个真实的工厂模式示例。但是代码在ReSharper中生成了一个关于构造函数中的虚拟成员调用的警告 引起警告的代码如下所示: abstract class Document { private List<Page> _pages = new List<Page>(); // Constructor calls abstract Factory method public Document() { this.C
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());
}
}
我确实理解为什么在构造函数中调用虚拟成员是个坏主意(如前所述)
我的问题是如何重构它,以便仍然使用工厂模式,但不在构造函数中调用虚拟成员
如果我只是从构造函数中删除对CreatePages
的调用,则使用者必须显式调用CreatePages
方法:
Document document = new Resume();
document.CreatePages();
我更喜欢这样的情况,即创建一份新的
简历
是实际创建包含页面的简历所需的全部工作。您可以在属性本身中完成
在这种情况下,Pages
属性可以在基类中标记为virtual
Resume
的假设代码可能如下所示:
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;
}
}
}
private List\u pages=null;
公共覆盖列表页
{
得到
{
如果(页面==null)
{
_pages=新列表();
_pages.Add(new SkillsPage());
_添加(新教育页面());
_添加(新体验页面());
}
返回页面;
}
}
}
在这种情况下,页面将在首次访问
页面
属性时创建,而不是在执行时创建。重构的一种方法是预先传递页面,并将其传递给受保护的构造函数:
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()
};
}
}
公共抽象类文档{
受保护文档(IEnumerable页){
//如果可以添加到_页面,请不要使用AsReadOnly
_pages=pages.ToList().AsReadOnly();
}
// ...
}
公开课简历:文件{
公共简历():基本(CreatePages()){
}
私有静态IEnumerable CreatePages(){
返回新页面[]{
新技能集(),
新建教育页面(),
新体验()
};
}
}
另外,我不确定这与工厂方法有什么关系。你的帖子说明了这个问题。这个怎么样?它使用惰性初始化,其中页面仅在需要时创建(而不是在构造函数中创建)
另外,请注意,factory方法可见性已更改为protected
,以将其隐藏起来,不供公众使用
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());
}
}
}
我的问题是如何重构它,以便仍然使用工厂模式,但不在构造函数中调用虚拟成员
根据定义
在基于类的编程中,工厂方法模式是一种创造性模式,它使用工厂方法来处理创建对象的问题,而不指定要创建的对象的确切类
工厂方法不打算从构造函数中使用,因为将要创建的对象的确切类在构造时是已知的。比如说,
如果文档
必须在构建时创建所有页面
,则无需工厂方法即可创建,因为它完全知道要创建的所有页面
但如果文档
必须在构建之后创建页面
,可能需要多次,那么工厂方法是有用的
我更喜欢这样的情况,即创建一份新的简历才是真正创建一份包含页面的简历所需要的
因此,如果在构建时创建所有页面
,则无需使用工厂方法模式即可重写此具体示例:
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
方法Add
允许从Resume
构造函数中使用,因为Document
对象已完全构造并准备好使用
方法Add
受到保护,因此只能从Document
或派生类添加页面
只需将Resume
标记为sealed
?@EkoostikMartin如果OP明天醒来想要声明styleshresume:Resume
?@EkoostikMartin:我不只是想警告消失,我想知道如何实现这一点。仍然可以对Resume
进行子类化。我建议寻找更好的真实示例。这将在页面
的每次访问中不断添加页面。我想在Pages
属性中,你会检查\u Pages==null
并且只调用CreatePages
。你的代码没有意义,CreatePages()
有一个无效的返回,那么myResume.Pages
在这个设计中给了我什么?@EkoostikMartin是的,我刚刚看到了!现在修好了。感谢tipI,我希望检查\u pages==null
或\u pages.Count==0
在抽象类中。@comecme Yes这是一个选项。但是,这种方式更加灵活,因为子类可以选择要做什么,而不是对所有子类都有一个通用行为。我认为这不符合工厂方法的条件,因为已经没有方法了。好吧,您可以像“方法”一样使用属性。为什么你想要和方法成员紧密结合……根据这是一个工厂方法的例子。他们错了吗?@comecme是的,我有理由肯定他们错了:首先,工厂方法不能是void
,它必须返回一些东西。
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;
}
}
}
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