2017-05-05 14 views
9

Tôi đang cố gắng hiểu những gì thực sự xác định khớp nối chặt chẽ. Tôi có read a number của posts về chủ đề này nhưng có một điều vẫn không phù hợp với tôi.Tóm tắt chức năng liên quan bằng cách sử dụng giao diện và khớp nối chặt chẽ

Tôi hiểu rằng các lớp học nên được tiêm vào các lớp khác bằng cách sử dụng giao diện của họ thay vì triển khai cụ thể. Tôi cũng hiểu rằng nếu một lớp học tuân thủ một giao diện thì bất kỳ lớp nào sử dụng giao diện được tiêm có thể gọi các hàm công khai được định nghĩa trong giao diện và mong đợi chức năng tương tự.

interface iFormatter() 
{ 
    public function format(array $order): array 
} 

public class OrderFormatter implements iFormatter 
{ 
    public function format(array $order): array 
    { 
     // ... 

     return $formattedArray; 
    } 
} 

public class OrderGenerator implements iGenerator 
{ 
    private $formatter; 

    public function __construct(iFormatter $formatter) 
    { 
     $this->formatter = $formatter; 
    } 

    public function generate() 
    { 
      // ... 

      return $this->formatter->format($order); 
    } 
} 

Vì vậy, tôi nghĩ rằng trong trường hợp chỉ những thay đổi định dạng, điều này sẽ được định nghĩa là lỏng lẻo;

$example = new OrderGenerator(new CarOrderFormatter); 
$example->generate(); 

$example = new OrderGenerator(new VanOrderFormatter); 
$example->generate(); 

Điều tôi hoàn toàn không biết là khi bạn trừu tượng trách nhiệm với nhau nhưng những lớp đó vẫn gắn liền với nhau. Một cái gì đó như

$example = new CarOrderGenerator(new CarOrderFormatter); 
$example->generate(); 

$example = new VanOrderGenerator(new VanOrderFormatter); 
$example->generate(); 

Có bạn có thể vượt qua trong một định dạng khác nhau để các máy phát điện, nhưng chắc chắn thường xuyên hơn mà không phải một số lỗi có thể xảy ra trong format chức năng nếu nó là hy vọng dữ liệu nhất định từ generate chức năng trong lớp bê tông XXXOrderGenerator ?

Vì vậy, tôi tin Tôi đã tóm tắt trách nhiệm đối với các lớp của riêng mình trong ví dụ trên và mặc dù giao diện đã được sử dụng Tôi không chắc chắn nếu điều này vẫn được kết nối chặt chẽ hoặc kỹ thuật lỏng lẻo? Hoặc nếu tôi đã bỏ lỡ điểm hoàn toàn ...

Trả lời

6

Các lớp được cho là được kết hợp chặt chẽ khi một lớp có sự phụ thuộc vào người khác hoặc dựa vào nội bộ hoặc chi tiết của người kia.

Trong trường hợp ví dụ đầu tiên bạn đã đặt OrderGenerator và OrderFormatter không được kết hợp chặt chẽ bởi vì cả hai đều không phụ thuộc vào nhau: cả hai đều phụ thuộc vào iFormatter. Một cách khác để đặt nó là OrderFormatter không biết gì về OrderGenerator và OrderGenerator không biết gì về OrderFormatter, nó chỉ biết rằng đối tượng được truyền cho nó thực hiện chức năng 'định dạng'. Bạn đã làm nổi bật điều này khi bạn vượt qua hoặc CarOrderFormatter hoặc VanOrderFormatter để OrderGenerator mà không có kết quả bất lợi.

Trong trường hợp của ví dụ thứ hai khi CarOrderFormatter được chuyển đến CarOrderGenerator, bạn đã đề cập rằng chắc chắn lỗi sẽ xảy ra với bạn thông qua nói VanOrderFormatter cho CarOrderGenerator. Nếu mã trong CarOrderGenerator dựa vào các chi tiết thực hiện của CarOrderFormatter thì các lớp được kết hợp chặt chẽ ngay cả khi giao diện iFormatter là cái mà CarOrderGenerator nhìn thấy. Mã này sẽ gây nhầm lẫn bởi vì CarOrderGenerator đang nói với 'hợp đồng' của nó mà nó không quan tâm những gì định dạng được thông qua nhưng rõ ràng nó. Do đó, nó sẽ tốt hơn nếu xét về độ rõ ràng của mã nếu CarOrderGenerator nói rõ ràng rằng bạn chỉ có thể truyền một CarOrderFormatter cho hàm tạo của nó. Sự trừu tượng (có nghĩa là, việc sử dụng giao diện) không phải là một điều xấu tuy nhiên và suy nghĩ cần phải được đưa vào cách chính xác giao diện cần được xác định. Nói ví dụ thay vì chỉ có một giao diện iFormatter thay vì bạn có iCarOrderFormatter và iVanOrderFormatter cả hai đều được định nghĩa giống nhau nhưng CarOrderGenerator yêu cầu iCarOrderFormatter và VanOrderGenerator yêu cầu iVanOrderFormatter.Ví dụ bạn có thể trở thành:

$example = new CarOrderGenerator(new CarOrderFormatter 
$example->generate(); 
$example = new CarOrderGenerator(new SportsCarOrderFormatter) 
$example->generate(); 

hoặc

$example = new VanOrderGenerator(new PassengerVanOrderFormatter 
$example->generate(); 
$example = new VanOrderGenerator(new CargoVanOrderFormatter) 
$example->generate(); 

Điều quan trọng để nhận ra là giao diện được giới thiệu để tạo sự linh hoạt trong những gì có thể được truyền cho các máy phát điện mà không có nó gây ra vấn đề.

+0

Cảm ơn bạn, điều này đã xóa hết cho tôi rất nhiều – myol

1

Bạn chính xác rằng nếu bạn chạy vào ô tô/van concretes cho iGenerator và iFormatter bạn có thể sẽ có một thời gian xấu pha trộn các phụ thuộc. Nhưng vấn đề là bạn không nên chạy vào tình huống đó, nếu bạn làm bạn nên quay trở lại bản vẽ vì bạn đã rẽ sai.

Tôi không biết ví dụ của bạn có được giả tạo hay dựa chặt chẽ (hay không) cho miền sự cố của bạn. Trong cả hai trường hợp, vấn đề là thiết kế kém. Giao diện của bạn phải thể hiện một trách nhiệm hoặc mục đích duy nhất. Để kết thúc này, mục đích của iOrderGenerator và iFormatter là gì? Ví dụ của bạn tất cả iOrderGenerator hiện là bọc iFormatter. Tôi có thể tái cấu trúc iOrderGenerator ra khỏi thiết kế vì nó không phục vụ mục đích gì cả. Vấn đề. Giải quyết.

Được rồi, đừng bỏ qua cách dễ dàng và nói iOrderGenerator đã có một mục đích. Vâng mục đích đó phải khác với iFormatter. Nếu bạn thực hiện giao diện đang bước qua ranh giới của mục đích duy nhất của nó hoặc sao chép mục đích của giao diện khác, bạn có thể có thiết kế xấu. Vì vậy, như một ví dụ, giả sử mục đích của iFormatter là in các đơn đặt hàng khác nhau dựa trên loại lệnh (van hoặc ô tô). Sau đó, iOrderGenerator chịu trách nhiệm tạo đơn đặt hàng (thuộc bất kỳ loại nào). Nhưng tôi có thể có nhiều cách để tạo một đơn đặt hàng. CsvOrderGenerator hoặc XmlOrderGenerator hoặc BulkOrderGenerator (nhưng không bao giờ CarOrderGen hoặc VanOrderGen).

Nit chọn trên ví dụ của bạn, chúng tôi có thể chỉ ra các vấn đề thiết kế giải thích cách bạn kết thúc với một tình huống khó chịu khi bạn đang cố gắng để giới thiệu một khái niệm mã tốt.

Bạn là iFormatter là giao diện kém vì nó trả về giá trị mơ hồ (mảng). Bất cứ điều gì sử dụng giá trị trả về sẽ cần kiến ​​thức thân mật về cách bê tông làm việc để biết những gì các mục đã hoặc không được chứa trong mảng. Tức là làm thế nào tôi biết có một giá trị khóa orderId mà không đọc mã hoặc xem kết quả (gỡ lỗi/in). Thay vào đó, iFormatter sẽ trả về một kiểu được mô tả đúng nghĩa là CarFormat hoặc VanFormat, mỗi cái có thể thực hiện một iFormat cung cấp các trình tiếp cận chung cho số thứ tự và giá.

iOrderGenerator có thể sẽ tạo ra một iOrder. Mà có thể có một phương thức getFormatter: iFormatter.

Những thay đổi đó có thể làm sạch thiết kế và cho biết mục đích rõ ràng hơn cho từng bê tông sẽ không dẫn bạn đến bước ban đầu nếu như.

+0

Cảm ơn bạn đã chỉ ra các giá trị trả về mơ hồ, đã thay đổi quan điểm của tôi về cách cấu trúc các lớp hoàn toàn. Tôi cảm thấy bạn xứng đáng có một tiền thưởng cho lời giải thích của bạn quá. – myol

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