2011-04-14 57 views
5

Tôi đang cân nhắc một trong hai cách khác nhau để triển khai mẫu nhà máy trong PHP. Tôi không biết liệu những biến thể này có tên riêng hay không, bây giờ tôi sẽ gọi chúng là nhà máy nội bộ và nhà máy bên ngoài.Nhà máy bên trong và bên ngoài

nhà máy nội bộ: Các phương pháp nhà máy được thực hiện trong các lớp chính nó như là một phương pháp public static

<?php 
class Foo 
{ 
    protected 
     $loadedProps = false; 

    public static factory ($id) 
    { 
     $class = get_called_class(); 
     $item = new $class ($id); 
     if ($item -> loadedProps()) 
     { 
      return ($item); 
     } 
    } 

    public function loadedProps() 
    { 
     return ($this -> loadedProps); 
    } 

    protected function loadPropsFromDB ($id) 
    { 
     // Some SQL logic goes here 
    } 

    protected function __construct ($id) 
    { 
     $this -> loadedProps = $this -> loadPropsFromDB ($id); 
    } 
} 
?> 

nhà máy bên ngoài: Các nhà máy và các mục nó khởi được thực hiện như những thực thể riêng biệt

<?php 

class Foo 
{ 
    protected 
     $loadedProps = false; 

    public function loadedProps() 
    { 
     return ($this -> loadedProps); 
    } 

    protected function loadPropsFromDB ($id) 
    { 
     // Some SQL logic goes here 
    } 

    public function __construct ($id) 
    { 
     $this -> loadedProps = $this -> loadPropsFromDB ($id); 
    } 
} 

abstract class FooFactory 
{ 
    public static factory ($id) 
    { 
     $item = new Foo ($id); 
     if ($item -> loadedProps()) 
     { 
      return ($item); 
     } 
    } 
} 
?> 

Bây giờ có vẻ như với tôi rằng mỗi người đều có giá trị của nó.

Trước đây cho phép bạn ẩn công cụ xây dựng khỏi thế giới bên ngoài. Điều này có nghĩa là cách duy nhất bạn có thể tạo đối tượng Foo là thông qua nhà máy. Nếu trạng thái của mục không thể được nạp từ DB thì nhà máy sẽ trả về NULL mà bạn có thể kiểm tra dễ dàng trong mã.

if ($item = Foo::factory ($id)) 
{ 
    // ... 
} 
else 
{ 
    // The item failed to load. Handle error here 
} 

Nhà máy cũng có thể tạo đối tượng của bất kỳ phân lớp Foo nào mà không sửa đổi.

Tuy nhiên, dường như có một số hạn chế. Đầu tiên, lớp học phải thực hiện nhà máy, có thể đặt trách nhiệm vào lớp thực sự thuộc về nơi khác. Phiên bản nhà máy nội bộ chắc chắn dẫn đến một lớp lớn hơn so với phiên bản nhà máy bên ngoài.

Đối với nhà máy bên ngoài, nó sạch hơn vì nhà máy không nằm trong chính lớp và tôi không phải lo lắng về việc lớp học chịu trách nhiệm nhiều hơn mức cần thiết. Nhà máy bên ngoài cũng có thể phù hợp hơn với tiêm phụ thuộc.

Tuy nhiên, nó có tập hợp các hạn chế riêng. Đầu tiên và quan trọng nhất, hàm tạo của mục được xây dựng trong nhà máy phải được công khai vì PHP không có khái niệm về các gói và không có mức bảo vệ 'gói' cho các thành viên lớp. Điều này có nghĩa là không có gì ngăn chặn một coder từ chỉ làm mới Foo() và bỏ qua các nhà máy (Điều này có thể làm cho đơn vị thử nghiệm dễ dàng hơn, mặc dù).

Vấn đề khác là FooFactory chỉ có thể tạo đối tượng Foo, không phải bất kỳ lớp con nào của nó. Điều này có thể có xung quanh bằng cách thêm một tham số khác vào FooFactory để chỉ định tên lớp, nhưng sau đó nhà máy sẽ phải kiểm tra nội bộ mà lớp đối tượng đã chỉ định thực tế là hậu duệ của Foo.

Vì vậy, về cơ bản, giá trị tương đối của hai cách tiếp cận là gì và bạn sẽ đề xuất điều gì?

Ngoài ra, nếu chúng có tên riêng hơn nhà máy bên trong hoặc bên ngoài, tôi muốn biết chúng.

Trả lời

7

Trên thực tế, nhà máy được thành lập Creational Design Patterns, vì vậy bạn có thể đọc về mục đích của họ trong Sách GOF hoặc ít Sourcemaking:

  • Abstract Factory - Tạo một thể hiện của một số gia đình của các tầng lớp
  • Builder - tách cấu trúc đối tượng khỏi biểu thị của nó
  • Phương thức nhà máy - Tạo một thể hiện của một số lớp dẫn xuất
  • Object Pool - Tránh mua lại tốn kém và giải phóng nguồn lực bằng cách tái chế các đối tượng không còn được sử dụng
  • Prototype - Một thể hiện đầy đủ khởi tạo được sao chép hoặc nhân bản

Có một số chồng chéo trong các mô hình này, đặc biệt là giữa Phương thức Factory, Abstract Factory và Builder và sự khác biệt thậm chí còn mờ hơn khi bạn không tạo ra các họ của các đối tượng, mà chỉ là một loại đối tượng. Vì vậy, có, cho đơn giản, chúng ta hãy giả sử nhà máy nội bộ và bên ngoài là những điều khoản đúng.

Cá nhân, tôi luôn ưu tiên một Nhà máy bên ngoài qua Nhà máy nội bộ do lý do bạn đã cung cấp: Tôi có thể sử dụng Dependency Injection và có thể separate the responsibilities. Kể từ static methods are death to testability và có thể là considered harmful do khớp nối mà chúng giới thiệu, tôi sẽ làm cho Nhà máy trở thành đối tượng thực sự thay vào đó và sử dụng các phương pháp không tĩnh.

Hai nhược điểm bạn đề cập không thực sự là nhược điểm.

Tôi không thể nghĩ ra lý do tại sao tôi muốn prevent a developer từ các đối tượng instantiating mà một nhà máy tạo ra. Trên thực tế, khi Unit-Testing tôi sẽ muốn tự tạo đối tượng đó và thay thế bất kỳ phụ thuộc nào bằng Mocks and Stubs. I also dont believe that developers should be babysitted too much. Do tính chất kịch bản của PHP, việc thay đổi ctor từ private thành public là cách quá dễ dàng để ngăn chặn hiệu quả anyways.

Vì vấn đề khác của Nhà máy không thể tạo các lớp khác, điều đó không đúng. Ý tưởng của một Nhà máy thực sự là tạo ra nhiều loại khác nhau của một nhóm đối tượng. Ngay cả phương thức Factory cũng được cho phép tạo các lớp con. Cho dù bạn thực hiện điều đó với một chuyển đổi/trường hợp hoặc với các phương pháp khác nhau trên nhà máy là tùy thuộc vào bạn. Cũng không có lý do gì để không kết hợp các nhà máy với các nhà xây dựng hoặc có các nhà máy của các nhà máy mà lần lượt đóng gói logic để tạo ra một đối tượng. Vì vậy, loại bỏ sự cần thiết cho bất kỳ kiểm tra nội bộ bạn đề cập (mà cũng có thể được đáp ứng với typehints).

Cách thay thế khả thi khác đối với các Nhà máy sẽ là sử dụng Dependency Injection Container, như Symfony Components DIC và quản lý đối tượng của bạn thông qua vùng chứa đó chủ yếu.

+0

'Off-topic:' Trên một lưu ý ngẫu nhiên tôi thấy nó hài hước mà cả hai bạn đang nói về cùng một điều khi bạn cũng có cùng tên người dùng. Trong một giây, tôi nghĩ bạn đang nói chuyện với chính mình. – Tek

+0

@Tek yeah, Gordon trả lời Gordon. Nhưng tôi là Gordon ™ :) – Gordon

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