Thật ra nó khá đơn giản:
Thay vì có một Trình xây dựng thực hiện cài đặt của bạn,
// c-family pseudo-code
public class Thing {
public Thing (a, b, c, d) { this.x = a; this.y = b; /* ... */ }
}
... yêu cầu nhà xây dựng của bạn làm ít hoặc không làm gì cả, và viết một phương thức được gọi .init
hoặc .initialize
, phương thức này sẽ làm những gì nhà xây dựng của bạn thường làm.
public class Thing {
public Thing () {}
public void initialize (a, b, c, d) {
this.x = a; /*...*/
}
}
Vì vậy, bây giờ thay vì chỉ đi như:
Thing thing = new Thing(1, 2, 3, 4);
Bạn có thể đi:
Thing thing = new Thing();
thing.doSomething();
thing.bind_events(evt_1, evt_2);
thing.initialize(1, 2, 3, 4);
Lợi ích ở đây là giờ đây bạn có thể sử dụng phép tiêm phụ thuộc / đảo ngược kiểm soát dễ dàng hơn trong các hệ thống của mình.
Thay vì nói
public class Soldier {
private Weapon weapon;
public Soldier (name, x, y) {
this.weapon = new Weapon();
}
}
Bạn có thể xây dựng người lính, cho anh ta một phương pháp trang bị, nơi bạn đưa cho anh ta một vũ khí và THEN gọi tất cả các chức năng còn lại của hàm tạo.
Vì vậy, bây giờ, thay vì phân loại kẻ thù trong đó một người lính có súng lục và người khác có súng trường và người khác có súng ngắn, và đó là điểm khác biệt duy nhất, bạn chỉ có thể nói:
Soldier soldier1 = new Soldier(),
soldier2 = new Soldier(),
soldier3 = new Soldier();
soldier1.equip(new Pistol());
soldier2.equip(new Rifle());
soldier3.equip(new Shotgun());
soldier1.initialize("Bob", 32, 48);
soldier2.initialize("Doug", 57, 200);
soldier3.initialize("Mike", 92, 30);
Cùng đối phó với sự hủy diệt. Nếu bạn có nhu cầu đặc biệt (loại bỏ trình lắng nghe sự kiện, loại bỏ các trường hợp khỏi mảng / bất kỳ cấu trúc nào bạn đang làm việc, v.v.), thì bạn sẽ gọi chúng theo cách thủ công để bạn biết chính xác thời điểm và địa điểm trong chương trình đang diễn ra.
BIÊN TẬP
Như Kryotan đã chỉ ra, bên dưới, câu trả lời này là "Làm thế nào" của bài viết gốc , nhưng không thực sự làm tốt công việc "Tại sao".
Như bạn có thể thấy trong câu trả lời ở trên, có thể không có nhiều sự khác biệt giữa:
var myObj = new Object();
myObj.setPrecondition(1);
myObj.setOtherPrecondition(2);
myObj.init();
và viết
var myObj = new Object(1,2);
trong khi chỉ có một hàm xây dựng lớn hơn.
Có một đối số được đưa ra cho các đối tượng có 15 hoặc 20 điều kiện trước, điều này sẽ khiến cho một nhà xây dựng rất, rất khó để làm việc và nó sẽ làm cho mọi thứ dễ nhìn và dễ nhớ hơn, bằng cách kéo những thứ đó ra ngoài giao diện , để bạn có thể thấy cách khởi tạo hoạt động, cao hơn một cấp.
Cấu hình tùy chọn của các đối tượng là một phần mở rộng tự nhiên cho điều này; tùy chọn thiết lập các giá trị trên giao diện, trước khi làm cho đối tượng chạy.
JS có một số phím tắt tuyệt vời cho ý tưởng này, dường như không phù hợp với các ngôn ngữ giống như c được gõ mạnh hơn.
Điều đó nói rằng, rất có thể, nếu bạn đang xử lý một danh sách đối số dài trong hàm tạo của bạn, thì đối tượng của bạn quá lớn và quá nhiều, như vậy. Một lần nữa, đây là một sở thích cá nhân và có những trường hợp ngoại lệ xa và rộng, nhưng nếu bạn chuyển 20 thứ vào một đối tượng, rất có thể bạn có thể tìm ra cách làm cho đối tượng đó làm ít hơn, bằng cách tạo ra các đối tượng nhỏ hơn .
Một lý do thích hợp hơn và một lý do có thể áp dụng rộng rãi là việc khởi tạo một đối tượng phụ thuộc vào dữ liệu không đồng bộ mà hiện tại bạn không có.
Bạn biết rằng bạn cần đối tượng, vì vậy dù sao bạn cũng sẽ tạo ra nó, nhưng để nó hoạt động chính xác, nó cần dữ liệu từ máy chủ hoặc từ một tệp khác mà bây giờ nó cần tải.
Một lần nữa, cho dù bạn chuyển dữ liệu cần thiết vào một init khổng lồ hay xây dựng giao diện không thực sự quan trọng đối với khái niệm này, cũng quan trọng đối với giao diện của đối tượng và thiết kế hệ thống của bạn ...
Nhưng về mặt xây dựng đối tượng, bạn có thể làm một cái gì đó như thế này:
var obj_w_async_dependencies = new Object();
async_loader.load(obj_w_async_dependencies.async_data, obj_w_async_dependencies);
async_loader
có thể được thông qua tên tệp, hoặc tên tài nguyên hoặc bất cứ thứ gì, tải tài nguyên đó - có thể nó tải các tệp âm thanh hoặc dữ liệu hình ảnh hoặc có thể tải các số liệu thống kê ký tự đã lưu ...
... và sau đó nó sẽ đưa dữ liệu đó trở lại obj_w_async_dependencies.init(result);
.
Loại động này được tìm thấy thường xuyên trong các ứng dụng web.
Không nhất thiết phải trong quá trình xây dựng của một đối tượng, đối với các ứng dụng cấp cao hơn: ví dụ: các phòng trưng bày có thể tải và khởi tạo ngay lập tức, sau đó hiển thị ảnh khi chúng truyền vào - đó không thực sự là khởi tạo không đồng bộ, nhưng ở đó thường thấy hơn trong các thư viện JavaScript.
Một mô-đun có thể phụ thuộc vào một mô-đun khác, và vì vậy việc khởi tạo mô-đun đó có thể được hoãn lại cho đến khi quá trình tải các phụ thuộc hoàn tất.
Về các trường hợp cụ thể của trò chơi này, hãy xem xét một Game
lớp thực tế .
Tại sao chúng ta không thể gọi .start
hoặc .run
trong nhà xây dựng?
Tài nguyên cần phải được tải - phần còn lại của mọi thứ đã được xác định khá nhiều và rất tốt để đi, nhưng nếu chúng ta thử chạy trò chơi mà không có kết nối cơ sở dữ liệu, hoặc không có kết cấu hoặc mô hình hoặc âm thanh hoặc cấp độ, thì sẽ không được một trò chơi đặc biệt thú vị ...
... vậy thì, sự khác biệt giữa những gì chúng ta thấy của một điển hình Game
, ngoại trừ việc chúng ta đặt cho phương thức "đi trước" của nó một cái tên thú vị hơn .init
(hoặc ngược lại, phá vỡ sự khởi tạo cách xa nhau hơn, để tách riêng tải, thiết lập những thứ đã được tải và chạy chương trình khi mọi thứ đã được thiết lập).