Làm thế nào tôi nên thêm chức năng cho một đối tượng đã tồn tại?


25

Tôi có một giao diện có một số chức năng nhất định được xác định rõ. Hãy cùng nói nào:

interface BakeryInterface {
  public function createCookies();
  public function createIceCream();
}

Điều này hoạt động tốt cho hầu hết các cài đặt của giao diện, nhưng trong một vài trường hợp, tôi cần thêm một số chức năng mới (như có lẽ được đưa vào một phương thức mới, createBrownies()). Cách tiếp cận rõ ràng / ngây thơ để làm điều này sẽ là mở rộng giao diện:

interface BrownieBakeryInterface extends BakeryInterface {
  public function createBrownies();
}

Nhưng có một nhược điểm khá lớn là tôi không thể thêm chức năng mới mà không sửa đổi API hiện có (như thay đổi lớp để sử dụng giao diện mới).

Tôi đã suy nghĩ về việc sử dụng một bộ chuyển đổi để thêm chức năng sau khi khởi tạo:

class BrownieAdapter {
  private brownieBakery;

  public function construct(BakeryInterface bakery) {
    this->brownieBakery = bakery;
  }

  public function createBrownies() {
    /* ... */
  }
}

Mà sẽ net cho tôi một cái gì đó như:

bakery = new Bakery();
bakery = new BrownieBakery(bakery);
bakery->createBrownies();

Đây có vẻ là một giải pháp tốt cho vấn đề, nhưng tôi tự hỏi liệu tôi có đánh thức các vị thần cũ bằng cách làm điều đó không. Là bộ chuyển đổi con đường để đi? Có một mô hình tốt hơn để làm theo? Hay tôi thực sự chỉ nên cắn viên đạn và chỉ mở rộng giao diện ban đầu?


Delphi có các lớp trợ giúp, nó giống như thêm các phương thức vào các lớp hiện có mà không thực sự sửa đổi chúng. Ví dụ Delphi có một lớp TBitmap được xác định trong đơn vị đồ họa của nó, bạn có thể tạo một lớp trình trợ giúp thêm, giả sử, một hàm Flip vào TBitmap. Miễn là lớp trình trợ giúp nằm trong phạm vi, bạn có thể gọi MyBitmap.Flip;
Hóa đơn

Câu trả lời:


14

Bất kỳ mẫu Cơ thể Xử lý nào cũng có thể phù hợp với mô tả, tùy thuộc vào yêu cầu chính xác, ngôn ngữ và mức độ trừu tượng cần thiết của bạn.

Cách tiếp cận thuần túy sẽ là mẫu Decorator , thực hiện chính xác những gì bạn đang tìm kiếm, tự động thêm trách nhiệm cho các đối tượng. Nếu bạn thực sự đang xây dựng các tiệm bánh, nó chắc chắn là quá mức cần thiết và bạn chỉ nên đi với Adaptor.


Đây chính xác là những gì tôi cần: Tôi nhận ra rằng việc sử dụng bộ chuyển đổi sẽ làm hỏng việc tiêm phụ thuộc, nhưng sử dụng một công cụ trang trí sẽ khắc phục điều đó.

5

Nghiên cứu khái niệm tái sử dụng theo chiều ngang , nơi bạn có thể tìm thấy những thứ như Traits , Lập trình hướng đối tượng vẫn còn thử nghiệm nhưng đã được sản xuất và Mixins đôi khi bị ghét .

Một cách trực tiếp để thêm các phương thức vào một lớp cũng phụ thuộc vào ngôn ngữ lập trình. Ruby cho phép vá khỉ trong khi dựa trên nguyên mẫu của Javascript kế thừa , nơi các lớp không thực sự tồn tại, bạn tạo một đối tượng và chỉ sao chép nó và tiếp tục thêm vào nó, ví dụ:

var MyClass = {
    do : function(){...}
};

var MyNewClass = new MyClass;
MyClass.undo = function(){...};


var my_new_object = new MyNewClass;
my_new_object.do();
my_new_object.undo();

Cuối cùng, bạn cũng có thể mô phỏng tái sử dụng theo chiều ngang hoặc "sửa đổi" thời gian chạy và "bổ sung" hành vi của lớp / đối tượng với sự phản chiếu .


4

Nếu có một yêu cầu mà bakerycá thể phải thay đổi hành vi của nó một cách linh hoạt (tùy thuộc vào hành động của người dùng, v.v.) thì bạn nên chọn mẫu Trang trí .

Nếu bakerykhông thay đổi hành vi của nó một cách linh hoạt nhưng bạn không thể sửa đổi Bakery class(API bên ngoài, v.v.) thì bạn nên chọn mẫu Bộ điều hợp .

Nếu bakerykhông thay đổi hành vi của nó một cách linh hoạt và bạn có thể sửa đổi Bakery classthì bạn nên mở rộng giao diện hiện tại (như bạn đã đề xuất ban đầu) hoặc giới thiệu một giao diện mới BrownieInterface và cho phép Bakerythực hiện hai giao diện BakeryInterfaceBrownieInterface.
Nếu không, bạn sẽ thêm độ phức tạp không cần thiết vào mã của mình (sử dụng mẫu Trang trí) mà không có lý do chính đáng!


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.