2012-06-29 23 views
8

Trên www.dofactory.com Tôi đã tìm thấy một ví dụ về thế giới thực của Mẫu Nhà máy. Nhưng mã tạo ra một cảnh báo trong ReSharper về một cuộc gọi thành viên ảo trong hàm tạo.Làm thế nào để ngăn chặn mô hình Phương thức nhà máy gây ra cảnh báo về cuộc gọi thành viên ảo trong hàm tạo?

Mã gây ra cảnh báo như sau:

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

Trong mã tốn, bạn có thể sau đó chỉ cần sử dụng:

Document document = new Resume(); 

Tôi hiểu tại sao đó là một ý tưởng tồi để gọi một ảo thành viên trong hàm tạo (như được giải thích here).

Câu hỏi của tôi là cách bạn có thể cấu trúc lại điều này để vẫn sử dụng mẫu nhà máy, nhưng không có cuộc gọi thành viên ảo trong hàm tạo.

Nếu tôi chỉ muốn loại bỏ các cuộc gọi đến CreatePages từ các nhà xây dựng, người tiêu dùng sẽ phải gọi một cách rõ ràng CreatePages phương pháp:

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

tôi nhiều hơn nữa thích tình huống mà tạo ra một mới Resume là tất cả những gì cần thiết để tạo một trang Tiếp tục chứa các trang.

+0

Chỉ cần đánh dấu 'Tiếp tục' là' niêm phong'? – EkoostikMartin

+1

@EkoostikMartin nếu OP sẽ thức dậy vào ngày mai muốn tuyên bố 'StylishResume: Resume' thì sao? –

+0

@EkoostikMartin: Tôi không chỉ muốn cảnh báo biến mất, tôi muốn biết điều này có thể được thực hiện như thế nào. Vẫn có thể phân lớp 'Tiếp tục'. – comecme

Trả lời

2

Một cách để cấu trúc lại này sẽ được đi qua các trang trả trước, và chuyển chúng tới một constructor bảo vệ:

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

T.B. Tôi không chắc chắn điều này đã làm gì với phương pháp nhà máy. Bài đăng của bạn minh họa Template Method Pattern.

+0

Theo [dofactory.com] (http://www.dofactory.com/Patterns/PatternFactory.aspx) nó là một ví dụ về một phương pháp nhà máy. Họ có sai không? – comecme

+2

@comecme Có, tôi chắc chắn rằng họ sai: vì một điều, phương pháp nhà máy không thể là 'void', nó phải trả lại một cái gì đó. – dasblinkenlight

0

Bạn có thể thực hiện trong chính thuộc tính.

Trong trường hợp đó, thuộc tính Pages có thể được đánh dấu là virtual trong lớp cơ sở.

Mã theo giả thuyết cho Resume có thể trông như thế này:

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

     } 
    } 

Trong trường hợp này, các trang sẽ được tạo ra về tiếp cận đầu tiên Pages bất động sản, và không trên ctor thực hiện.

+0

Tôi không nghĩ rằng điều này sẽ đủ điều kiện như là một phương pháp nhà máy, vì không có phương pháp nữa. – comecme

+0

Vâng, bạn sử dụng một 'thuộc tính' như một phương thức" ". Tại sao bạn muốn cặp vợ chồng khó khăn với các thành viên phương pháp ... – Tigran

1

Điều này thì sao? Nó sử dụng khởi tạo lười biếng, nơi các trang được tạo ra chỉ khi cần thiết (thay vì tạo chúng trong constructor)

Ngoài ra, lưu ý hiển thị phương thức nhà máy được thay đổi thành protected để ẩn nó khỏi sử dụng công cộng.

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 Góp ý: Cá nhân tôi không thích có mà _pages biến toàn cầu vì nó có thể giúp bạn có được vào rắc rối nếu chia sẻ giữa nhiều phương pháp và chủ đề. Tôi thà đi cho mô hình phương thức nhà máy như mô tả trong cuốn sách GoF.Dưới đây là gợi ý của tôi:

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; 
     } 
    } 
} 
+0

Điều này sẽ tiếp tục thêm các trang trên mỗi truy cập của 'Trang'. Tôi cho rằng bên trong thuộc tính 'Pages' bạn sẽ kiểm tra nếu' _pages == null' và chỉ gọi 'CreatePages' nếu nó là. – comecme

+0

@comecme Chỉ cần cập nhật mã của tôi :) nó sẽ là tốt bây giờ – GETah

+1

Mã của bạn không có ý nghĩa, 'CreatePages()' có một void trở lại, do đó, những gì hiện 'myResume.Pages' cho tôi trong thiết kế này? – EkoostikMartin

1

Câu hỏi của tôi là làm thế nào bạn có thể cấu trúc này để vẫn sử dụng mô hình nhà máy, nhưng không có cuộc gọi thành viên ảo trong constructor.

Theo định nghĩa

Trong lập trình dựa trên lớp, các factory method là một mẫu creational trong đó sử dụng phương pháp nhà máy để đối phó với các vấn đề của việc tạo ra đối tượng mà không chỉ định lớp chính xác của đối tượng đó sẽ được tạo ra.

phương pháp nhà máy không có ý định được sử dụng từ hàm tạo vì lớp chính xác của đối tượng sẽ được tạo ra được biết đến tại thời điểm xây dựng. Ví dụ,

  1. nếu Document phải tạo mọi Pages lúc xây dựng, sau đó nó có thể làm điều đó mà không cần phương pháp nhà máy kể từ khi nó biết chính xác tất cả các trang được tạo ra

  2. nhưng nếu Document phải tạo Pages sau sau thời gian thi công và có thể nhiều, sau đó phương pháp nhà máy rất hữu ích

tôi nhiều hơn nữa thích situat ion, nơi tạo ra một Resume mới là tất cả những gì cần thiết để tạo ra một Resume chứa các trang.

Vì vậy, nếu tất cả Pages là được tạo ra vào thời điểm xây dựng, ví dụ cụ thể này có thể được viết lại mà không cần sử dụng các phương pháp nhà máy mẫu:

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. Phương pháp Add được phép sử dụng từ Resume hàm tạo, vì đối tượng Document được xây dựng hoàn chỉnh và sẵn sàng để sử dụng.

  2. Phương thức Add được bảo vệ, vì vậy chỉ có thể thêm các trang từ Document hoặc các lớp dẫn xuất.

Các vấn đề liên quan