Mô hình thiết kế nhà máy trong PHP là gì?


88

Điều này làm tôi bối rối, nói một cách đơn giản nhất thì nó làm gì? Giả vờ như bạn đang giải thích với mẹ hoặc ai đó gần như hài lòng.


115
Mẹ tôi sẽ không hiểu nó bằng cách nào ...
Bruno Reis

6
@JasonDavis Tôi tiếp tục trả lời câu hỏi của bạn ... Tôi bắt đầu cảm thấy như một kẻ theo dõi.
Tyler Carter

Câu trả lời:


175

Một nhà máy tạo ra một đối tượng. Vì vậy, nếu bạn muốn xây dựng

 class A{
    public $classb;
    public $classc;
    public function __construct($classb, $classc)
    {
         $this->classb = $classb;
         $this->classc = $classc;
    }
  }

Bạn sẽ không muốn dựa vào việc phải thực hiện đoạn mã sau mỗi khi tạo đối tượng

$obj = new ClassA(new ClassB, new Class C);

Đó là nơi mà nhà máy sẽ đi vào. Chúng tôi xác định một nhà máy để đảm nhận việc đó cho chúng tôi:

class Factory{
    public function build()
    {
        $classc = $this->buildC();
        $classb = $this->buildB();
        return $this->buildA($classb, $classc);

    }

    public function buildA($classb, $classc)
    {
        return new ClassA($classb, $classc);
    }

    public function buildB()
    {
        return new ClassB;
    }

    public function buildC()
    {
        return new ClassC;
    }
}

Bây giờ tất cả những gì chúng ta phải làm là

$factory = new Factory;
$obj     = $factory->build();

Lợi thế thực sự là khi bạn muốn thay đổi lớp học. Giả sử chúng tôi muốn vượt qua ClassC khác:

class Factory_New extends Factory{
    public function buildC(){
        return new ClassD;
    }
}

hoặc ClassB mới:

class Factory_New2 extends Factory{
    public function buildB(){
        return new ClassE;
    }
}

Bây giờ chúng ta có thể sử dụng kế thừa để dễ dàng sửa đổi cách lớp được tạo ra, để đưa vào một tập hợp các lớp khác.

Một ví dụ điển hình có thể là lớp người dùng này:

class User{
    public $data;
    public function __construct($data)
    {
        $this->data = $data;
    }
}

Trong lớp $datanày là lớp chúng ta sử dụng để lưu trữ dữ liệu của mình. Bây giờ đối với lớp này, giả sử chúng ta sử dụng Session để lưu trữ dữ liệu của mình. Nhà máy sẽ trông như thế này:

class Factory{
    public function build()
    {
        $data = $this->buildData();
        return $this->buildUser($data);
    }

    public function buildData()
    {
        return SessionObject();
    }

    public function buildUser($data)
    {
        return User($data);
    }
}

Bây giờ, giả sử thay vào đó chúng tôi muốn lưu trữ tất cả dữ liệu của mình trong cơ sở dữ liệu, việc thay đổi nó thực sự đơn giản:

class Factory_New extends Factory{
    public function buildData()
    {
        return DatabaseObject();
    }
}

Nhà máy là một mẫu thiết kế mà chúng tôi sử dụng để kiểm soát cách chúng tôi đặt các đối tượng lại với nhau và việc sử dụng các mẫu nhà máy chính xác cho phép chúng tôi tạo các đối tượng tùy chỉnh mà chúng tôi cần.


3
Đó là rất nhiều đánh máy. Bây giờ tôi sẽ phải đưa nó lên wiki của mình vào một lúc nào đó.
Tyler Carter

1
Tốt và hữu ích. Mũ cho bạn đời.
stefgosselin

1
Sự khác biệt / lợi ích của mã của bạn là gì $obj = $factory->build();hơn $obj = new whateverClass();? Ngoài ra, trong một lớp khác (ví dụ classZ) phụ thuộc vào dữ liệu của classA, bạn sẽ sử dụng phương thức factory ở đâu trong classZ? Về cơ bản, bạn vẫn đang khởi tạo một lớp (classZ) trong một lớp (classA), có nghĩa là không có thử nghiệm. ví dụ: nhà máy dường như chỉ là một tải mã để thực hiện newthông qua một phương thức thay vì chỉ sử dụng new.
James

19

Giống như một nhà máy ngoài đời thực, nó tạo ra một thứ gì đó và trả lại nó.

Hãy tưởng tượng một cái gì đó như thế này

$joe = new Joe();
$joe->say('hello');

hoặc một phương pháp nhà máy

Joe::Factory()->say('hello');

Việc thực hiện phương thức factory sẽ tạo một thể hiện mới và trả về nó.


1
Ví dụ tuyệt vời, làm tôi ngạc nhiên về mức độ đa dạng của việc triển khai cho mẫu này. Khi được gọi tĩnh, tôi giả sử người ta có thể lấy một tham chiếu đến phiên bản để sử dụng lại phiên bản đó sau này không? tức là $ joe = Joe :: Factory () -> say ('xin chào');
stefgosselin

chắc chắn như ở 5.6 người ta cũng có thể làm (new Joe ()) -> say ('xin chào');
Pancho

12

Mô hình thiết kế nhà máy rất tốt khi bạn đang xử lý nhiều tài nguyên và muốn triển khai tính trừu tượng ở mức cao.

Hãy chia phần này thành các phần khác nhau.

Giả sử bạn phải triển khai tính trừu tượng và người dùng lớp của bạn không cần quan tâm đến những gì bạn đã triển khai trong định nghĩa lớp.

Anh ấy / cô ấy chỉ cần lo lắng về việc sử dụng các phương thức lớp của bạn.

ví dụ: Bạn có hai cơ sở dữ liệu cho dự án của mình

class MySQLConn {

        public function __construct() {
                echo "MySQL Database Connection" . PHP_EOL;
        }

        public function select() {
                echo "Your mysql select query execute here" . PHP_EOL;
        }

}

class OracleConn {

        public function __construct() {
                echo "Oracle Database Connection" . PHP_EOL;
        }

        public function select() {
                echo "Your oracle select query execute here" . PHP_EOL;
        }

}

Lớp Factory của bạn sẽ đảm nhận việc tạo đối tượng cho kết nối cơ sở dữ liệu.

class DBFactory {

        public static function getConn($dbtype) {

                switch($dbtype) {
                        case "MySQL":
                                $dbobj = new MySQLConn();
                                break;
                        case "Oracle":
                                $dbobj = new OracleConn();
                                break;
                        default:
                                $dbobj = new MySQLConn();
                                break;
                }

                return $dbobj;
        }

}

Người dùng chỉ cần chuyển tên của loại cơ sở dữ liệu

$dbconn1 = DBFactory::getConn("MySQL");
$dbconn1->select();

Đầu ra:

MySQL Database Connection
Your mysql select query execute here

Trong tương lai, bạn có thể có cơ sở dữ liệu khác thì bạn không cần phải thay đổi toàn bộ mã chỉ cần chuyển loại cơ sở dữ liệu mới và mã khác sẽ chạy mà không cần thực hiện bất kỳ thay đổi nào.

$dbconn2 = DBFactory::getConn("Oracle");
$dbconn2->select();

Đầu ra:

Oracle Database Connection
Your oracle select query execute here

Hy vọng điều này sẽ giúp ích.


1

Nói chung, một "nhà máy" sản xuất một cái gì đó: trong trường hợp Lập trình-Định hướng Đối tượng, một "Mẫu thiết kế nhà máy" tạo ra các đối tượng.

Không quan trọng nếu đó là ngôn ngữ PHP, C # hay bất kỳ ngôn ngữ hướng đối tượng nào khác.


1

Mẫu thiết kế nhà máy (Factory Pattern) dành cho khớp nối lỏng lẻo. Giống như ý nghĩa của nhà máy, dữ liệu đến nhà máy (sản xuất dữ liệu) đến người dùng cuối cùng. Bằng cách này, nhà máy phá vỡ mối liên hệ chặt chẽ giữa nguồn dữ liệu và quy trình dữ liệu.



0

Câu trả lời này liên quan đến bài đăng khác trong đó Daniel White cho biết sử dụng nhà máy để tạo kết nối MySQL bằng cách sử dụng mẫu nhà máy.

Đối với kết nối MySQL, tôi muốn sử dụng mẫu singleton vì bạn muốn sử dụng cùng một kết nối để truy cập cơ sở dữ liệu chứ không phải tạo một kết nối khác.


0

Cách tiếp cận cổ điển để khởi tạo một đối tượng là:

$Object=new ClassName();

PHP có khả năng tạo động một đối tượng từ tên biến bằng cú pháp sau:

$Object=new $classname;

trong đó biến $ classname chứa tên của lớp mà người ta muốn khởi tạo.

Vì vậy, bao thanh toán đối tượng cổ điển sẽ giống như sau:

function getInstance($classname)
{
  if($classname==='Customer')
  {
    $Object=new Customer();
  }
  elseif($classname==='Product')
  {
    $Object=new Product();
  }
  return $Object;
}

và nếu bạn gọi hàm getInstance ('Sản phẩm'), nhà máy này sẽ tạo và trả về đối tượng Sản phẩm. Ngược lại, nếu bạn gọi hàm getInstance ('Khách hàng'), nhà máy này sẽ tạo và trả về đối tượng kiểu Khách hàng (được tạo từ lớp Khách hàng ()).

Không cần điều đó nữa, người ta có thể gửi 'Sản phẩm' hoặc 'Khách hàng' (tên chính xác của các lớp hiện có) dưới dạng giá trị của biến để khởi tạo động:

$classname='Product';
$Object1=new $classname; //this will instantiate new Product()

$classname='Customer';
$Object2=new $classname; //this will instantiate new Customer()

0

Nói một cách dễ hiểu, đối với bản ghi, một nhà máy như @Pindatjuh đã nói, trả về một đối tượng.

Vậy, sự khác biệt với một hàm tạo là gì? (điều đó cũng tương tự)

  1. một phương thức khởi tạo sử dụng thể hiện của chính mình.
  2. Một cái gì đó tôi muốn một cái gì đó cao cấp hơn và tôi không muốn làm cồng kềnh đối tượng (hoặc thêm các phần phụ thuộc).
  3. Hàm tạo được gọi khi mỗi cá thể được tạo. Đôi khi bạn không muốn điều đó.

    Ví dụ, giả sử rằng mỗi khi tôi tạo một đối tượng của Tài khoản lớp, tôi đọc từ cơ sở dữ liệu một tệp và sử dụng nó làm mẫu.

Sử dụng hàm tạo:

class Account {
      var $user;
      var $pwd;
      var ...
      public __construct() {
         // here i read from the file
         // and many other stuff
      }
}

Sử dụng nhà máy:

class Account {
      var $user;
      var $pwd;
      var ...
}
class AccountFactory {
      public static Create() {
         $obj=new Account();
         // here we read the file and more stuff.
         return $obj;
      }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.