-
Design Pattern
- Singleton Design Pattern
- Factory Design Pattern
- Factory Method Design Pattern
- Abstract Factory Design Pattern
- Builder Design Pattern
- Prototype Design Pattern
- Object Pool Design Pattern
- Chain of Responsibility Design Pattern
- Command Design Pattern
- Interpreter Design Pattern
- Iterator Design Pattern
- Mediator Design Pattern
- Memento Design Pattern
- Observer Design Pattern
- Observer Design Pattern - Xử Lý Exception
- Strategy Design Pattern
- Template Method Design Pattern
- Visitor Design Pattern
- Null Object Design Pattern
- Adapter Design Pattern
- Bridge Design Pattern
- Composite Design Pattern
- Decorator Design Pattern
- Flyweight Design Pattern
- Proxy Design Pattern
- S.O.L.I.D
- Clean code
- Lập trình socket
- Java Core
- Multi-Thread
- Spring
- Java Web
- Memory Caching
- Message Queue
- DevOps
- Xây dựng một nền tảng
- MongoDB
- MySQL timestamp
- Properties vs yaml
- Kotlin
- Lập Trình Machine Learning với PyTorch
- Mã Nguồn Mở
- Ezy HTTP
- Free Chat
- Một số kinh nghiệm với Git
- Review cho đồng nghiệp!
- Setup Dev Environment
- Hello World
- Create a Server Project
- Handle Client Requests
- Using ezyfox-server-csharp-client
- Using ezyfox-es6-client
- Client React.js Interaction
- Build And Deploy In Local

Phải thay thế được!
Nguyên tắc này nói rằng, nếu một lớp A là con của lớp B, thì chúng ta có thay thế lớp A cho lớp B mà không làm cho chương trình bị phá huỷ, và ở trong hình minh hoạ thì để di chuyển thì chúng ta có thể chọn bất cứ loại xe ô tô nào chúng ta muốn mà vẫn đảm bảo được tốc độ và khả năng vận chuyển. Và thật thú vị là nguyên tắc này được giới thiệu bởi một người phụ nữ có tên Barbara Liskov. Trên thực tế thì nguyên tắc này chúng ta vẫn tuân thủ hàng ngày mà không nhận ra, tuy nhiên cũng có trường hợp chúng ta vi phạm nguyên tắc này một cách vô ý.
Bài toán thực tế
Có lẽ trong thời đại của microservices như hiện nay thì rất có khả năng chúng ta phải lấy dữ liệu từ nhiều nguồn khác nhau, có thể là từ MongoDB hay MySQL, hãy nói chúng ta có một interface dùng chung thế này:
public interface DatabaseRepo<I, E> {
void save(E entity);
E findById(I id);
long increase(String field);
}
Và chúng ta có 1 lớp sử dụng kiểu thế này:
public class UserService {
private DatabaseRepo<Long, User> userRepo;
private DatabaseRepo<String, IdProvider> idProvider;
public void save(User user) {
long userId = userRepo.increase("userId", "maxId");
user.setId(userId);
userRepo.save(user);
}
}
Phân tích vấn đề
Trong đoạn chương trình ở trên, chúng ta tạo ra userId tăng dần, set nó vào đối tượng user và save xuống database. Nhưng vấn đề ở đây là với MongoDB thì chúng ta có toán tử $inc
trong khi MySQL thì không, điều này dẫn đến việc nếu chúng ta tạo ra 1 lớp thế này:
public class MySQLDatabaseRepo<I, E> implements DatabaseRepo<I, E> {
@Override
public long increase(String id, String field) {
throw new UnsupportedOperationException("unsupported");
}
}
Và chúng ta set nó vào lớp UserService
nó sẽ làm hỏng chương trình của chúng ta, cụ thể là nghiệp vụ save user này.
Giải pháp
Để chương trình của chúng ta hoạt động bình thường thì ở lớp MySQLDatabaseRepo
hàm increase
sẽ không được phép ném ra UnsupportedOperationException
. Và rất may cho chúng ta là MySQL có hỗ trợ auto increment id, vậy nên chúng ta sẽ chỉ cần thay đổi lớp MySQLDatabaseRepo
thế này là được:
public class MySQLDatabaseRepo<I, E> implements DatabaseRepo<I, E> {
@Override
public long increase(String id, String field) {
return 0;
}
}
Hoặc chúng ta cũng có thể tạo 1 procedure ở MySQL để tạo ra id tăng dần, lúc đó lớp MySQLDatabaseRepo
sẽ kiểu thế này:
public class MySQLDatabaseRepo<I, E> implements DatabaseRepo<I, E> {
@Override
public long increase(String id, String field) {
return callProcedue(id, field).getResult();
}
}
Nhìn chung sẽ không có 1 giải pháp chung cho mọi tình huống, chính vì vậy, dựa vào logic của chương trình mà chúng ta sẽ đưa ra cài đặt phù hợp.
Tổng kết
Việc nâng cấp, thay thế hay sử dụng chung các lớp có thể sẽ xảy ra, và nhiệm vụ của chúng ta là phải đảm bảo cho mọi thứ hoạt động tốt giống như trước đó bằng cách áp dụng nguyên tắc Liskov Substitution
này. Tuy nhiên để đảm bảo được nguyên tắc này hoạt động hiệu quả, chúng ta cũng sẽ cần sử dụng đên unit test và integration test để phát hiện các logic bất thường trong code của chúng ta trước khi trên khai lên các môi trường chạy thực tế.
-
Design Pattern
- Singleton Design Pattern
- Factory Design Pattern
- Factory Method Design Pattern
- Abstract Factory Design Pattern
- Builder Design Pattern
- Prototype Design Pattern
- Object Pool Design Pattern
- Chain of Responsibility Design Pattern
- Command Design Pattern
- Interpreter Design Pattern
- Iterator Design Pattern
- Mediator Design Pattern
- Memento Design Pattern
- Observer Design Pattern
- Observer Design Pattern - Xử Lý Exception
- Strategy Design Pattern
- Template Method Design Pattern
- Visitor Design Pattern
- Null Object Design Pattern
- Adapter Design Pattern
- Bridge Design Pattern
- Composite Design Pattern
- Decorator Design Pattern
- Flyweight Design Pattern
- Proxy Design Pattern
- S.O.L.I.D
- Clean code
- Lập trình socket
- Java Core
- Multi-Thread
- Spring
- Java Web
- Memory Caching
- Message Queue
- DevOps
- Xây dựng một nền tảng
- MongoDB
- MySQL timestamp
- Properties vs yaml
- Kotlin
- Lập Trình Machine Learning với PyTorch
- Mã Nguồn Mở
- Ezy HTTP
- Free Chat
- Một số kinh nghiệm với Git
- Review cho đồng nghiệp!
- Setup Dev Environment
- Hello World
- Create a Server Project
- Handle Client Requests
- Using ezyfox-server-csharp-client
- Using ezyfox-es6-client
- Client React.js Interaction
- Build And Deploy In Local