2010-12-11 45 views
27

Chúng ta đều biết sự khác biệt giữa một phương thức Constructor và một phương pháp do người dùng định nghĩa Initialize().Phương thức khởi tạo() vs Constructor(), sử dụng đúng cách để tạo đối tượng

Câu hỏi của tôi tập trung vào thực tiễn thiết kế tốt nhất để tạo đối tượng. Chúng tôi có thể đặt tất cả mã Initialize() vào Constructor() và ngược lại (di chuyển tất cả mã khởi động sang phương thức Initialize và gọi phương thức này từ Constructor).

Hiện tại, thiết kế một lớp mới, tôi tạo bất kỳ phiên bản mới nào bên trong constructor() và di chuyển bất kỳ mã khởi động nào khác vào phương thức Initialize().

Điểm giao dịch tốt nhất theo quan điểm của bạn là gì?

Trả lời

23

Tôi nghĩ rằng có nhiều khía cạnh cần được xem xét:

  • Một constructor nên khởi tạo một đối tượng trong một cách mà nó đang ở trạng thái sử dụng được.

  • Nhà xây dựng chỉ nên khởi tạo đối tượng, không thực hiện công việc nặng nhọc.

  • Nhà xây dựng không nên trực tiếp hoặc gián tiếp gọi cho các thành viên ảo hoặc mã bên ngoài.

Vì vậy, trong hầu hết các trường hợp, không nên bắt buộc phương thức khởi tạo.

Trong trường hợp khởi tạo liên quan đến việc đặt đối tượng vào trạng thái có thể sử dụng (ví dụ: khi cần thực hiện công việc nặng hoặc thành viên ảo hoặc cần gọi bên ngoài), thì phương pháp khởi tạo là một ý tưởng hay.

+0

Đặt tốt. Trong quá khứ tôi cũng đã dựa vào việc sử dụng các phương thức 'initialize()' trên các hàm tạo khi không trực tiếp khởi tạo đối tượng của bạn, như sử dụng một mẫu nhà máy. Bạn có nghĩ đây là sự cân nhắc có liên quan không? – Ray

3

Tôi đã tìm thấy bản thân mình suy nghĩ về điều này một chút công bằng gần đây (do đó tìm kiếm câu hỏi này) và trong khi tôi không có một câu trả lời tôi nghĩ rằng tôi muốn chia sẻ suy nghĩ của tôi.

  • Constructors 'lý tưởng' chỉ nên thiết lập trạng thái đối tượng, tức là: một vài ví dụ:

this.member = member;

Theo tôi đây chơi độc đáo với IoC, thừa kế, thử nghiệm và chỉ có mùi hấp dẫn.

nâng Tuy nhiên nặng đôi khi cần thiết vì vậy những gì tôi đã cố gắng để làm là:

  • đèo trong nâng nặng.

Điều đó có nghĩa là trừu tượng mã khởi tạo đó sang lớp khác và chuyển mã đó vào. Điều này thường có thể xảy ra nếu việc nâng hạng nặng không thực sự là trách nhiệm đối tượng của bạn.

Nếu điều này là không thể và bạn cần phải khởi tạo trạng thái cho lớp học của bạn trước khi sử dụng, sau đó thêm phương thức khởi tạo.Điều này không thêm sự phụ thuộc thời gian vào mã của bạn nhưng điều này không nhất thiết phải là một điều xấu đặc biệt là khi sử dụng container IoC:

Say CarEngine đòi hỏi một DrivingAssistComputer, và DrivingAssistComputer nhu cầu để làm khởi động nặng, tức Tải tất cả các thông số, kiểm tra điều kiện thời tiết, vv Một điều cần lưu ý là CarEngine không trực tiếp tương tác với các DrivingAssistComputer, nó chỉ cần nó để có mặt, làm điều riêng của mình ở bên cạnh. Trong thực tế, động cơ có thể không hoạt động đúng cách nếu không có DrivingAssistComputer làm việc của nó ở chế độ nền (thay đổi một số trạng thái ở đâu đó). Nếu chúng ta đang sử dụng IoC sau đó chúng ta có:

// Without initialise (i.e. initialisation done in computer constructor) 
public CarEngine(FuelInjectors injectors, DrivingAssistComputer computer) { 
    this.injectors = injectors; 
    // No need to reference computer as we dont really interact with it. 
} 

... 

Vì vậy, những gì chúng tôi có ở đây là một cuộc tranh luận constructor đánh dấu computer như một dependancy nhưng không thực sự sử dụng nó. Vì vậy, đây là xấu xí, nhưng cho phép thêm một phương pháp khởi:

public CarEngine(FuelInjectors injectors, DrivingAssistComputer computer) { 
    this.injectors = injectors; 
    // This ofcourse could also be moved to CarEngine.Initialse 
    computer.Initialise(); 
} 

... 

Vẫn không một lớp gắn kết nhưng ít nhất chúng ta biết rằng chúng ta phụ thuộc vào máy tính mặc dù chúng tôi không trực tiếp tương tác với nó bên ngoài của các nhà xây dựng.

Một lựa chọn khác ofcourse là phải có một CarEngineFactory có quyền này:

CarEngine CreateEngine(FuelInjectors injectors) { 
    new DrivingAssistComputer().Initialise(); 
    return new CarEngine(injectors); 
} 

... 

Tuy nhiên, tôi nhận thấy các nhà máy và IoC chỉ nhầm lẫn giữa ma trận vì vậy tôi sẽ đi cho tùy chọn thứ hai.

Rất thích nghe một số suy nghĩ về điều này.

Chỉnh sửa 1: Một tùy chọn khác mà tôi đã bỏ lỡ ở trên là có phương thức Initialise nhưng di chuyển lời gọi này đến mô-đun khởi tạo IoC. Vì vậy, sáng tạo và khởi tạo vẫn còn phần nào đóng gói.

+0

+1 cho 'vượt qua trong việc nâng hạng nặng' - điều này có ý nghĩa với tôi –

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