Không nên để các thực thể phần mềm phụ thuộc vào những giao diện mà chúng không sử dụng đến.
Khi xây dựng một lớp, nhất là lớp trừu tƣợng, ngƣời ta thƣờng có xu hƣớng đƣa thật nhiều các thuộc tính và phƣơng thức vào lớp đó. Những lớp nhƣ vậy đƣợc gọi là lớp có giao diện bị ô nhiễm. Khi một lớp có giao diện bị ô nhiễm, nó sẽ trở lên phức tạp. Một thực thể khi muốn thực hiện một số việc đơn giản, nó buộc phải thực hiện với toàn bộ giao diện của lớp đó. Một lớp trừu tƣợng có giao diện bị ô nhiễm, khi một lớp muốn thừa kế nó với mong muốn chỉ thực hiện những nội dung mà nó quan tâm, tuy nhiên nó phải cài đặt cả phần giao diện mà không cần thiết. Điều này dẫn đến sự dƣ thừa không cần thiết, đồng thời tăng sự kết dính giữa các thực thể. Và khi thực hiện nâng cấp, mở rộng, ta sẽ phải chỉnh sửa giao diện đó. Việc này vi phạm nguyên lý đóng mở.
56 class Shape{
public:
virtual void Draw() const=0;
virtual void Transfer(double dx, double dy) = 0; };
class Square : public Shape{ protected:
double side; Point topLeft; public:
virtual void Draw() const;
virtual void Transfer(double dx, double dy); };
class Circle : public Shape{ protected:
double radius; Point center; public:
virtual void Draw() const;
virtual void Transfer(double dx, double dy); };
class Line : public Shape{ protected:
Point startPoint, endPoint; public:
virtual void Draw() const;
virtual void Transfer(double dx, double dy); };
Hình 2.1. Mô hình thừa kế lớp
Để minh họa sự vi phạm nguyên lý phân tách giao diện, ta thêm vào đoạn chƣơng trình trên chức năng tô màu, đƣa hàm Fill vào trong giao diện Shape.
enum ColorType {red, green, blue};
enum PatternType {solid, vertical, horizontal}; class Shape{
public:
57
virtual void Transfer(double dx, double dy) = 0;
virtual void Fill(ColorType color, PatternType pattern) = 0;
};
class Square : public Shape{ protected:
double side; Point topLeft; public:
virtual void Draw() const;
virtual void Transfer(double dx, double dy);
virtual void Fill(ColorType color, PatternType pattern); };
Các lớp con Circle, Line, Square sẽ phải cài đặt cụ thể cho phƣơng thức ảo Fill. Với các lớp Circle, Square thì điều này có ý nghĩa thực tế. Tuy nhiên với lớp Line, chức năng Fill sẽ không có ý nghĩa. Ta đã bắt buộc lớp Line phải định nghĩa hàm Fill mà không có ý nghĩa đối với nó. Khi đó ta nói nó đã vi phạm nguyên lý phân tách giao diện.
Để không bị vi phạm nguyên lý, ta có thể thực hiện thiết kế lại nhƣ sau:
Hình 2.2. Mô hình thừa kế lớp cải tiến
Một số chú ý khi xem xét nguyên lý phân tách giao diện:
Việc vi phạm nguyên lý phân tách giao diện sẽ dẫn đến vấn đề: nếu chấp nhận giao diện Shape bị ô nhiễm, lúc đó trong lớp Line, chúng ta cài đặt hàm Fill và một giải pháp đặt ra là cài đặt phƣơng thức rỗng. Hoặc trong giao diện Shape, hàm Fill không phải đặt là thuần ảo mà là hàm rỗng. Tuy nhiên cả hai giải pháp này sẽ có nguy cơ vi phạm nguyên lý thay thế Liskov.
Nguyên lý phân tách giao diện có mối liên hệ với nguyên lý đóng mở. Sự vi phạm nguyên lý phân tách giao diện có khả năng dẫn đến vi phạm nguyên lý đóng mở.
Để tránh vi phạm nguyên lý phân tách giao diện, ta nên giữ cho giao diện của lớp đối tƣợng đơn giản và gọn nhẹ, không nên để nó đảm nhận quá nhiều chức năng vì điều này dễ làm cho giao diện của nó bị ô nhiễm.
58