Là một người bắt đầu, một trong những người khác, một người chạy tốt


30

Tôi hiện đang làm việc trên một cơ sở mã có nhiều lớp thực hiện phương thức Bắt đầu. Điều này có vẻ giống như việc xây dựng hai giai đoạn đối với tôi, điều mà tôi luôn coi là một thực tiễn tồi tệ. Tôi không thể nói sự khác biệt giữa cái này và một constructor.

Khi nào thì thích hợp để sử dụng một phương thức bắt đầu thay vì xây dựng đối tượng bình thường?

Khi nào tôi nên sử dụng hàm tạo?

Chỉnh sửa: Tôi không nghĩ nó có liên quan nhưng ngôn ngữ lập trình là C #, nó có thể áp dụng như nhau cho Java hoặc C ++


3
Bạn có thể thêm một chút bối cảnh? Ngôn ngữ? Chủ đề vs chủ đề duy nhất? sự khác biệt giữa startvà các nhà xây dựng? v.v ...

@MichaelT Tôi có thể thấy lý do tại sao bạn hỏi, nhưng tôi quan tâm đến nguyên tắc chung phía sau khi nó phù hợp. Tôi lo ngại rằng nếu tôi đưa ra các ví dụ cụ thể từ cơ sở mã mà tôi đang làm việc, các câu trả lời sẽ quá tập trung vào các chi tiết và không phải là các câu hỏi cụ thể của tôi.
Dave Hillier

2
@DaveHillier Ví dụ: trong perl, đó là cách thực hành chuẩn (và tốt) để có một initphương thức nào đó bên ngoài newhàm - perldoc.perl.org/perlobj.html . Thành ngữ của một ngôn ngữ có thể hoạt động tốt ở đó và không phải trong các ngôn ngữ khác.

1
Ví dụ về các lớp với Startcác phương thức trong các API phổ biến bao gồm các luồng và đồng hồ bấm giờ.
luiscubal

1
Tính tôi trong số những người cần một mẫu mã để hiểu những gì bạn thực sự hỏi.
dùng16764

Câu trả lời:


44

Một Start()phương thức (như Run(), Execute()hoặc bất cứ thứ gì tương tự) là phù hợp khi chi phí xây dựng đối tượng thấp, nhưng chi phí sử dụng nó cao. Ví dụ: Một lớp đóng gói thuật toán tối ưu hóa đường dẫn tốt nhất. Việc thiết lập nó với một tập các tham số ( Xbình phương theo Ybình phương, với phương pháp đánh giá như vậy), nhưng có thể mất một lúc để thực thi. Nếu bạn muốn tạo 20 trong số các đối tượng này, bạn có thể muốn trì hoãn thực thi cho đến khi tất cả chúng được tạo - ví dụ, điều này cho phép bạn song song hóa chúng dễ dàng hơn.

Ngoài ra, nó có thể hữu ích khi bạn không biết khi nào cần phải bắt đầu đối tượng - có lẽ vì nó dựa trên đầu vào của người dùng hoặc logic chọn từ danh sách các khả năng.

Tất nhiên, điều này giả định rằng đó Start()là phương thức hữu ích trên đối tượng và không tương đương với một Initialize()phương thức. Nếu nó chỉ là một cách bổ sung để đặt thêm tham số, thì nó không nên tồn tại.


1
Một cách sử dụng khác cho phương thức start là khi hành động được thực hiện cũng tạo ra một luồng worker mới hoặc bộ đếm thời gian. Các nhà xây dựng không nên thực hiện loại nâng nặng này hoặc tạo ra các tác dụng phụ đáng kể (như tạo ra một chủ đề mới).
Ziv

50

Code Complete (và nhiều tài nguyên kỹ thuật phần mềm khác) nhấn mạnh việc khớp các lớp của bạn với các đối tượng trong thế giới thực. Tôi tin rằng lý do cơ bản cho điều này là nó khiến bạn có khả năng nắm bắt thực sự những gì bạn đang thực hiện, thay vì hack vào một ý tưởng vô hình.

Nếu bạn là người đăng ký theo lý thuyết này, tôi không thấy có gì sai khi thêm một Start()phương thức vào bất kỳ lớp nào, nếu đó là một đối tượng thực sự, cũng có trạng thái nghỉ. Nếu nó không có ý nghĩa gì cho đối tượng của bạn tồn tại trong khi không chạy (hoặc không có ý nghĩa gì đối với đối tượng của bạn đang chạy), thì tôi sẽ nói đó là một thực tế tồi.


16
Một sự tương tự tốt. Điều đáng chú ý là Start()có thể tương ứng với một công tắc bật / tắt (như một đèn báo) mà sau đó phải có Stop()hoặc một nút ấn (như nút In trên máy sao chép) khi nó khởi động và sau đó chạy cho đến khi hoàn tất.
Bobson

3
+1 cũng nói và chào mừng bạn đến với P.SE, những câu trả lời như thế này là một khởi đầu tuyệt vời.
Jimmy Hoffa

14

Bạn có thể sử dụng khởi tạo lười biếng.

Trong lập trình máy tính, khởi tạo lười biếng là chiến thuật trì hoãn việc tạo ra một đối tượng, tính toán một giá trị hoặc một số quy trình đắt tiền khác cho đến lần đầu tiên cần thiết.

Bằng cách đó, bạn tránh được khớp nối tạm thời, nghĩa là người tiêu dùng của lớp bạn phải gọi một số phương thức nhất định theo thứ tự nhất định. Phải gọi start()trước là cách để biết lớp học hoạt động như thế nào, điều này thật tệ vì bạn có thể thay đổi điều đó trong tương lai.

Trì hoãn việc khởi tạo đắt tiền cho đến khi cần lần đầu tiên ..

Thí dụ:

public class FooClass{

    private ExpensiveResource resource;
    private CheapResource cheap;

    public  FooClass(String someParameter){
        // constructor: initialize CheapResource cheap 
            // but NOT ExpensiveResource resource
    }

    public ExpensiveResource getExpensiveResource(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource
    }

    public String getExpensiveResourceName(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource.getName();
    }   

    public CheapResource getCheapResource(){
        return this.cheap;
    }

    private initializeExpensiveResource(){
        // do expensive initialization of field "resource"
    }

}

public class Test{
    public static void main (String args[]){

        FooClass foo = new FooClass("some string");
        CheapResource cr = foo.getCheapResource();
        String s = foo.getExpensiveResourceName(); 
          // just now is the expensive resource initialized

    }
}

5
Một lợi ích khác của việc khởi tạo lười biếng đáng chú ý là cần rất ít nỗ lực để hình thành nó thành một proxy ảo . Tùy thuộc vào tình huống, điều này có thể rất hữu ích để hiển thị một cái gì đó trong khi chờ tải tài nguyên (đặc biệt hữu ích cho những thứ như hình ảnh từ xa). Dựa trên câu hỏi ban đầu, tôi không nghĩ đây thực sự là những gì OP đang nhắm đến, nhưng nghĩ rằng nó đáng được đề cập.
Dan Albert

@DanAlbert bạn nói đúng, đó không phải là điều tôi yêu cầu nhưng vẫn thú vị
Dave Hillier
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.