2011-11-21 32 views
26

Khi bạn đang phân lớp các đối tượng và muốn mở rộng mã khởi tạo, có hai cách tiếp cận. Ghi đè __construct() và triển khai phương thức khởi tạo mà hàm tạo siêu lớp của bạn gọi.Thực hành tốt nhất, ghi đè __construct() so với việc cung cấp phương thức init()

Phương pháp 1:

class foo 
{ 
    public function __construct ($arg1, $arg2, $arg3) 
    { 
     // Do initialization 
    } 
} 

class bar extends foo 
{ 
    public function __construct ($arg1, $arg2, $arg3) 
    { 
     parent::__construct ($arg1, $arg2, $arg3); 
     // Do subclass initialization 
    } 
} 

Phương pháp 2

class foo 
{ 
    public function init() 
    { 
     // Dummy function 
    } 

    public function __construct ($arg1, $arg2, $arg3) 
    { 
     // Do subclass defined initialization 
     $this -> init(); 
     // Do other initialization 
    } 
} 

class bar extends foo 
{ 
    public function init() 
    { 
     // Do subclass initialization 
    } 
} 

Các tài liệu cho Zend Framework dường như làm nản lòng nhà xây dựng trọng và muốn bạn để ghi đè lên các phương pháp init, nơi cung cấp, nhưng điều này bằng cách nào đó chỉ doesn' Tôi cảm thấy đúng với tôi. Zend cũng có xu hướng làm một vài điều mà tôi không hài lòng vì vậy tôi không chắc liệu nó có nên được sử dụng như một ví dụ về thực hành tốt nhất hay không. Cá nhân tôi nghĩ rằng cách tiếp cận đầu tiên là đúng nhưng tôi đã nhìn thấy cách tiếp cận thứ hai thường đủ để tự hỏi nếu đó thực sự là những gì tôi nên làm.

Bạn có bất kỳ nhận xét nào về việc ghi đè __construct không? Tôi biết bạn phải cẩn thận khi nhớ gọi hàm tạo của lớp bậc trên, nhưng hầu hết các lập trình viên phải nhận thức được điều đó.

EDIT: tôi không sử dụng Zend, tôi chỉ sử dụng nó như một ví dụ về một codebase khuyến khích bạn sử dụng init() thay vì __construct trọng().

Trả lời

16

Có vẻ như cách tiếp cận thứ hai đang trì hoãn sự cố.

Nếu bạn có một lớp:

class bar2 extends bar // which already extends foo 
{ 
    public function init() 
    { 
    // You should then do anyway: 
    parent::init(); 

    // ... 
    } 
} 

Tôi sẽ đi cho các phương pháp tiếp cận đầu tiên quá, hợp lý hơn và đơn giản, kể từ khi parent::init() hoặc parent::__construct() cuộc gọi không có thể tránh được vô tận. Cách tiếp cận đầu tiên, IMO, ít gây nhầm lẫn.

3

Thứ nhất

Zend cũng có xu hướng để làm một vài điều mà tôi không hài lòng với

Bạn có thể giải quyết việc này đơn giản, bằng cách không sử dụng nó.

Nhưng thứ hai và quan trọng hơn, bạn nên ghi đè init() và không __construct()init() là một phần của hoạt động văn rằng Zend sử dụng và sử dụng nó đảm bảo rằng phần còn lại của ứng dụng của bạn là ở đó và tại chỗ. Làm khác phá vỡ dòng chảy của mô hình MVC của Zend và có thể dẫn đến hành vi kỳ quặc.

Sửa

Tôi nghĩ lý do chính đối với tôi là nó dừng lại nhà phát triển khác từ không quan trọng. Bạn có thể làm bất cứ điều gì với init() nhưng không phải với __construct() vì điều này cần phải chạy đúng với tất cả các thông số chính xác tại chỗ.

Đây là từ Zend Documents:

Trong khi bạn luôn có thể ghi đè lên nhà xây dựng bộ điều khiển hành động, chúng ta không khuyên này.Zend_Controller_Action :: _ construct() thực hiện một số nhiệm vụ quan trọng, chẳng hạn như đăng ký yêu cầu và phản hồi các đối tượng , cũng như bất kỳ đối số yêu cầu tùy chỉnh nào được truyền từ bộ điều khiển trước . Nếu bạn phải ghi đè hàm tạo, hãy đảm bảo gọi cho cha mẹ :: _construct ($ request, $ response, $ invokeArgs).

+0

Xin lỗi, tôi nên rõ ràng hơn một chút trong câu hỏi của tôi. Tôi không sử dụng Zend, tôi đang làm việc trên mã mà tôi dự định phát hành cho công chúng vào một thời điểm nào đó trong tương lai nếu tôi cảm thấy nó có thể hữu ích. Tôi chỉ sử dụng Zend làm ví dụ, vì nó có xu hướng sử dụng phương pháp init, và nếu một khung chính đang làm điều đó thì phải có một lý do. (ngay cả khi cá nhân tôi không thích khuôn khổ được đề cập nhiều) – GordonM

+0

Ah đúng. Có thể đáng để chỉnh sửa và đưa nó vào câu hỏi của bạn. Tôi đã chỉnh sửa bằng câu trả lời. –

0

tôi có thể thấy một lợi ích từ việc sử dụng init() thay vì __construct(): nếu những thay đổi chữ ký trong các nhà xây dựng, bạn sẽ phải cập nhật mỗi lớp được thừa kế để phù hợp với chữ ký mới.

Nếu init() không có tham số, điều này sẽ không xảy ra.

+1

Điều đó cũng không đúng nếu bạn có một lớp học với một init() thực hiện đã được phân lớp? Các lớp con cũng sẽ không được cập nhật để phản ánh các thay đổi trong phương thức init classclass? – GordonM

1

Tôi sẽ sử dụng hàm init vì nếu bạn ghi đè hàm tạo, bạn (thông thường) phải nhớ gọi hàm tạo của cha mẹ ở trên cùng của hàm tạo lớp con của bạn. Trong khi bạn có thể nhận thức được điều đó, bạn không thể đảm bảo rằng một nhà phát triển khác được giao nhiệm vụ duy trì ứng dụng của bạn sẽ được.

8

Hai tình huống duy nhất tôi có thể nghĩ đến là sử dụng init() là khi nhà xây dựng của bạn không công khai nhưng bạn cần cung cấp cho mọi người cơ hội để ảnh hưởng đến việc khởi tạo, ví dụ: trong một Singleton trừu tượng (mà bạn không muốn sử dụng anyway). Hoặc, giống như trong Zend Framework, khi bổ sung khởi chạy nên được trì hoãn (nhưng sau đó bạn không gọi init() từ nhà xây dựng).

Gọi phương thức trong phân lớp từ lớp cha được gọi là Template Method, nhân tiện. UseCase sẽ phối hợp một quy trình làm việc nhất định nhưng cho phép loại phụ ảnh hưởng đến các phần của nó. Điều này thường được thực hiện từ các phương thức thông thường. Lưu ý rằng hàm tạo của bạn không nên dàn xếp bất cứ thứ gì ngoài chỉ initialize the object into a valid state.

Bạn chắc chắn nên không gọi/cung cấp init() từ nhà xây dựng để ngăn các nhà phát triển phải nhớ gọi nhà xây dựng siêu kiểu. Trong khi đó có thể âm thanh thuận tiện, nó sẽ nhanh chóng mess lên hệ thống phân cấp thừa kế. Cũng lưu ý rằng nó lệch khỏi cách các đối tượng thường được khởi tạo và các nhà phát triển phải học hành vi mới này giống như họ phải học cách gọi hàm tạo của supertype.

+0

Tôi không muốn sử dụng đơn và đăng ký và những thứ tương tự, tôi nhận được đủ công việc và nó không làm cho cuộc sống của tôi trở nên dễ dàng hơn :) Giải pháp khởi tạo trì hoãn có vẻ như đây là cách sử dụng hợp lệ duy nhất cho việc này tiếp cận với tôi, và thậm chí sau đó tôi có cảm giác nó nên được sử dụng một cách tiết kiệm. Cảm ơn các con trỏ – GordonM

+0

BTW, câu trả lời của người khác đã được chấp nhận bởi vì tôi nghi ngờ bạn không thực sự cần đại diện vào thời điểm này. :) – GordonM

+0

@GordonM meh, và ở đây tôi đã suy nghĩ câu trả lời hữu ích nhất nhận được đánh dấu màu xanh lá cây: P – Gordon

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