Hãy để chúng tôi tạo một ví dụ hư cấu.
Lớp A
trong gói packageA
:
package packageA;
import packageB.B;
public class A {
B myB;
public A() {
this.myB = new B();
}
public void doSomethingThatUsesB() {
System.out.println("Doing things with myB");
this.myB.doSomething();
}
}
Lớp B
trong gói packageB
:
package packageB;
public class B {
public void doSomething() {
System.out.println("B did something.");
}
}
Như bạn thấy, A
phụ thuộc vào B
. Không thể sử dụng B
, A
. Nhưng nếu chúng ta muốn thay thế B
trong tương lai bằng một số BetterB
thì sao? Bây giờ, chúng ta bắt đầu để tạo ra một giao diện Inter
trong packageA
:
package packageA;
public interface Inter {
public void doSomething();
}
Để sử dụng giao diện này, chúng tôi import packageA.Inter;
và để B implements Inter
trong B
và thay thế tất cả các lần xuất hiện của B
trong A
với Inter
. Kết quả là phiên bản này được sửa đổi của A
:
package packageA;
public class A {
Inter myInter;
public A() {
this.myInter = ???; // What to do here?
}
public void doSomethingThatUsesInter() {
System.out.println("Doing things with myInter");
this.myInter.doSomething();
}
}
Tại thời điểm này, chúng ta thấy đã có sự phụ thuộc A
-B
đã biến mất: các import packageB.B;
không còn cần thiết. Chỉ có một vấn đề: chúng ta không thể khởi tạo một thể hiện của một giao diện. Nhưng Inversion of control đến để giải cứu. Thay vì instantiating một cái gì đó kiểu Inter
wihtin constructor A
's, chúng tôi sẽ yêu cầu cái gì mà implements Inter
như tham số cho các nhà xây dựng:
package packageA;
public class A {
Inter myInter;
public A(Inter myInter) {
this.myInter = myInter;
}
public void doSomethingThatUsesInter() {
System.out.println("Doing things with myInter");
this.myInter.doSomething();
}
}
Với cách tiếp cận này, chúng tôi bây giờ có thể thay đổi việc thực hiện cụ thể của Inter
trong A
theo ý thích. Giả sử bạn viết một lớp mới BetterB
:
package packageB;
import packageA.Inter;
public class BetterB implements Inter {
@Override
public void doSomething() {
System.out.println("BetterB did something.");
}
}
Bây giờ chúng ta có thể instantiante A
s với Inter
triển khai khác nhau:
Inter b = new B();
A aWithB = new A(b);
aWithB.doSomethingThatUsesInter();
Inter betterB = new BetterB();
A aWithBetterB = new A(betterB);
aWithBetterB.doSomethingThatUsesInter();
Và chúng tôi không cần phải thay đổi bất cứ điều gì trong A
. Mã này hiện đã được tách riêng và bạn có thể thay đổi việc triển khai cụ thể Inter
theo ý muốn, miễn là (các) hợp đồng của Inter
được (hài lòng). Đáng chú ý nhất, bạn có thể hỗ trợ mã, sẽ được tạo ra trong tương lai và thực hiện Inter
.
Tôi đánh giá cao các ấn phẩm của Robert C. Martin về các quy tắc SOLID về lập trình hướng đối tượng. Dưới đây là một số chi tiết về vấn đề của bạn: http://www.objectmentor.com/resources/articles/dip.pdf –