![translation](https://cdn.durumis.com/common/trans.png)
Đây là bài viết được dịch bởi AI.
Chọn ngôn ngữ
Văn bản được tóm tắt bởi AI durumis
- Giải thích phương thức lập trình hướng đối tượng để triển khai hệ thống đặt vé xem phim, giới thiệu các khái niệm về hợp tác, đối tượng, lớp và nhấn mạnh cấu trúc chương trình tuân theo cấu trúc miền.
- Đặc biệt, nó trình bày phương pháp giảm thiểu sự can thiệp từ bên ngoài và bảo đảm sự tự do cho lập trình viên bằng cách sử dụng tính tự trị và đóng gói của đối tượng, tách biệt giao diện và cài đặt.
- Ngoài ra, nó cũng giải thích cách viết mã linh hoạt và có thể mở rộng bằng cách sử dụng hợp tác, kế thừa và đa hình để tính toán phí giảm giá, nhấn mạnh tầm quan trọng của trừu tượng hóa và lợi thế của tổng hợp để tái sử dụng mã.
Hệ thống đặt vé xem phim
Xem xét yêu cầu
- Chúng tôi muốn triển khai một hệ thống đặt vé xem phim trực tuyến.
- Phim thể hiện thông tin cơ bản về phim.
- Tên, thời lượng chiếu, thông tin giá cả, v.v.
- Sự trình chiếu đại diện cho việc khán giả thực sự xem phim.
- Ngày chiếu, giờ chiếu, số thứ tự chiếu, v.v.
- Mọi người nói rằng họ đặt vé xem phim, nhưng thực ra họ đặt vé cho một buổi chiếu cụ thể.chiếuđúng hơn là nên nói như vậy.
- Điều kiện giảm giá
- Cho dù giá có giảm hay không
- Điều kiện theo thứ tự: Sử dụng số thứ tự chiếu để xác định việc giảm giá.
- Điều kiện theo thời gian: Sử dụng thời gian bắt đầu chiếu phim để xác định việc giảm giá.
- Chính sách giảm giá
- Xác định mức giá giảm.
- Chính sách giảm giá theo số tiền: Giảm một khoản tiền nhất định trong phí đặt vé.
- Chính sách giảm giá theo tỷ lệ: Giảm một tỷ lệ nhất định của mức giá gốc.
- Mỗi bộ phim có thể được gán một chính sách giảm giá hoặc không, và các điều kiện giảm giá có thể kết hợp nhiều điều kiện giảm giá với nhau.
- Nếu chính sách giảm giá được áp dụng nhưng điều kiện giảm giá không được đáp ứng hoặc chính sách giảm giá không được áp dụng, phí sẽ không được giảm.
Hướng tới lập trình hướng đối tượng
Hợp tác, đối tượng, lớp
- Lập trình hướng đối tượng là hướng tới đối tượng.
- Sau khi xác định lớp, chúng ta không nên bận tâm về việc lớp đó cần có thuộc tính và phương thức nào.
- Chúng ta cần phải xác định đối tượng nào sẽ có trạng thái và hành vi nào.
- Chúng ta không nên xem đối tượng là một thực thể độc lập mà là một thành viên của một cộng đồng hợp tác.
Cấu trúc chương trình theo cấu trúc của miền
- Miền là lĩnh vực mà người dùng sử dụng chương trình để giải quyết vấn đề.
- Nói chung, tên của lớp nên giống hoặc ít nhất là tương tự như tên của khái niệm miền tương ứng.
- Mối quan hệ giữa các lớp cũng nên được tạo ra giống với mối quan hệ giữa các khái niệm miền càng nhiều càng tốt để làm cho cấu trúc của chương trình dễ hiểu và dự đoán hơn.
Triển khai lớp
- Lớp được chia thành nội bộ và bên ngoài, và để thiết kế một lớp tốt, chúng ta cần phải quyết định phần nào sẽ được công khai và phần nào sẽ được ẩn.
- Các thuộc tính của đối tượng được ẩn bằng cách đặt private, và các phương thức cần thiết để thay đổi trạng thái nội bộ được mở ra bằng cách đặt public.
- Việc phân biệt nội bộ và bên ngoài của lớp đảm bảo tính tự trị của đối tượng, từ đó mang lại cho lập trình viên sự tự do triển khai.
Đối tượng tự trị
- Đối tượng cần phải là một đối tượng tự trị có trạng thái và hành vi.
- Việc kết hợp dữ liệu và chức năng bên trong đối tượng được gọi là đóng gói.
- Bằng cách kiểm soát quyền truy cập, chúng ta có thể giảm thiểu sự can thiệp từ bên ngoài, cho phép đối tượng tự quyết định hành động của mình.
- Nguyên tắc tách biệt giao diện và triển khai là một nguyên tắc chính cần tuân theo cho lập trình hướng đối tượng.
- Giao diện công khai: Phần có thể truy cập từ bên ngoài
- Triển khai: Phần chỉ có thể truy cập từ bên trong
Sự tự do của lập trình viên
- Vai trò của lập trình viên được chia thành người viết lớp và người lập trình khách hàng.
- Người viết lớp thêm kiểu dữ liệu mới
- Người lập trình khách hàng sử dụng kiểu dữ liệu được người viết lớp thêm
- Ẩn giấu triển khai
- Người viết lớp có thể ẩn giấu triển khai nội bộ bằng cách cung cấp cho người lập trình khách hàng những phần cần thiết.
- Người lập trình khách hàng chỉ cần biết giao diện, do đó có thể giảm khối lượng kiến thức.
Cộng đồng của các đối tượng hợp tác
- Khi thể hiện tiền, thay vì đơn giản là khai báo một biến kiểu Long, chúng ta nên đóng gói nó thành một đối tượng như Money. Điều này là bởi vì việc sử dụng đối tượng giúp truyền tải ý nghĩa tốt hơn và cho phép chúng ta thực hiện các xử lý tính toán lặp lại ở một nơi.
- Sự tương tác giữa các đối tượng để thực hiện một chức năng nào đó của hệ thống được gọi là hợp tác.
Câu chuyện ngắn về hợp tác
- Cách duy nhất đối tượng có thể tương tác với các đối tượng khác là bằng cách gửi hoặc nhận tin nhắn.
- Phương thức riêng của nó để xử lý tin nhắn đã nhận được được gọi là phương thức.
- Việc phân biệt giữa tin nhắn và phương thức là rất quan trọng, và từ đó khái niệm đa hình xuất hiện.
Tìm kiếm phí giảm giá
Bắt đầu hợp tác để tính toán phí giảm giá
- Lớp Movie không có logic chi tiết về chính sách giảm giá, nó đã ủy thác cho giao diện DiscountPolicy. Việc sử dụng kế thừa, đa hình và trừu tượng là rất quan trọng.
Chính sách giảm giá và điều kiện giảm giá
Kế thừa và đa hình
Sự phụ thuộc thời gian biên dịch và thời gian chạy
- Sự phụ thuộc của mã và thời điểm chạy có thể khác nhau.
- Sự phụ thuộc khác nhau giữa hai loại này càng lớn, mã càng khó hiểu hơn, nhưng nó sẽ trở nên linh hoạt và có thể mở rộng hơn.
Lập trình dựa trên sự khác biệt
- Kế thừa cho phép chúng ta thêm các lớp mới một cách dễ dàng và nhanh chóng dựa trên các lớp hiện có, và chúng ta có thể tái sử dụng triển khai của lớp cha.
- Phương pháp tạo lớp mới bằng cách chỉ thêm những phần khác biệt với lớp cha được gọi là lập trình dựa trên sự khác biệt.
Kế thừa và giao diện
- Kế thừa cho phép lớp con kế thừa tất cả các giao diện được cung cấp bởi lớp cha.
- Giao diện xác định danh sách các tin nhắn mà đối tượng có thể hiểu được.
public class Movie {
public Money calculateMovieFee(Screening screening) {
return fee.minus(discountPolicy.calculateDiscountAmount(screening));
}
- Movie đang gửi tin nhắn calculateDiscountAmount cho DiscountPolicy. Đối với Movie, nó không quan tâm đến việc instance của lớp nào trả lời, miễn là nó trả lời thành công.
- Do đó, cả AmountDiscountPolicy và PercentDiscountPolicy đều có thể thay thế DiscountPolicy để hợp tác với Movie.
- Việc lớp con thay thế lớp cha như vậy được gọi là upcasting. Điều này là bởi vì lớp con dường như được ép kiểu tự động thành lớp cha ở trên.
Đa hình
- Đa hình là khả năng đối tượng có thể trả lời khác nhau đối với cùng một tin nhắn, tùy thuộc vào kiểu của đối tượng.
- Movie gửi cùng một tin nhắn, nhưng thực tế phương thức nào sẽ được thực thi phụ thuộc vào lớp của đối tượng nhận được tin nhắn.
- Đa hình dựa trên thực tế là sự phụ thuộc của chương trình có thể khác nhau giữa thời gian biên dịch và thời gian chạy.
- Đa hình quyết định phương thức nào sẽ được thực thi tại thời điểm chạy, do đó nó được gọi là ràng buộc muộn hoặc ràng buộc động.
Giao diện và đa hình
- Nếu chúng ta không cần chia sẻ triển khai và chỉ muốn chia sẻ giao diện, chúng ta có thể sử dụng giao diện thay vì lớp trừu tượng.
Trừu tượng hóa và tính linh hoạt
Sức mạnh của trừu tượng hóa
- Ưu điểm của trừu tượng hóa
- Chúng ta có thể mô tả các chính sách của yêu cầu ở cấp độ cao hơn bằng cách xem xét riêng từng lớp trừu tượng.
- Thiết kế trở nên linh hoạt hơn.
Thiết kế linh hoạt
- Trừu tượng hóa ngăn chặn thiết kế bị ràng buộc với các tình huống cụ thể, do đó nó có thể tạo ra một thiết kế linh hoạt hơn.
Sự đánh đổi giữa lớp trừu tượng và giao diện
public abstract class DiscountPolicy {
private List conditions;
public DiscountPolicy(DiscountCondition... conditions) {
this.conditions = Arrays.asList(conditions);
}
public Money calculateDiscountAmount(Screening screening) {
for (DiscountCondition condition : conditions) {
if (condition.isSatisfiedBy(screening)) {
return getDiscountAmount(screening);
}
}
return Money.ZERO;
}
abstract protected Money getDiscountAmount(Screening screening);
}
public class NoneDiscountPolicy extends DiscountPolicy {
@Override
protected Money getDiscountAmount(Screening screening) {
return Money.ZERO;
}
- Hiện tại, NoneDiscountPolicy thực sự không cần thiết vì nếu không có điều kiện giảm giá trong phương thức calculateDiscountAmount() của DiscountPolicy, nó sẽ trả về 0, không có vấn đề gì. Tuy nhiên, đối với người dùng, họ cần phải cung cấp cho Movie một chính sách None không có giảm giá làm đối số, do đó chúng tôi đã thêm nó.
- Do đó, về mặt khái niệm, lớp NoneDiscountPolicy hơi gây nhầm lẫn, vì vậy chúng ta có thể sửa đổi nó như sau để dễ hiểu hơn.
public interface DiscountPolicy {
Money calculdateDiscountAmount(Screening screening);
}
public abstract class DefaultDiscountPolicy implements DiscountPolicy {
private List conditions;
public DefaultDiscountPolicy(DiscountCondition... conditions) {
this.conditions = Arrays.asList(conditions);
}
public Money calculateDiscountAmount(Screening screening) {
for (DiscountCondition condition : conditions) {
if (condition.isSatisfiedBy(screening)) {
return getDiscountAmount(screening);
}
}
return Money.ZERO;
}
abstract protected Money getDiscountAmount(Screening screening);
}
public class NoneDiscountPolicy implements DiscountPolicy {
@Override
public Money calculateDiscountAmount(Screening screening) {
return Money.ZERO;
}
}
public class PercentDiscountPolicy extends DefaultDiscountPolicy {
private double percent;
public PercentDiscountPolicy(double percent, DiscountCondition... conditions) {
super(conditions);
this.percent = percent;
}
@Override
protected Money getDiscountAmount(Screening screening) {
return screening.getMovieFee().times(percent);
}
}
public class AmountDiscountPolicy extends DefaultDiscountPolicy {
private Money discountAmount;
public AmountDiscountPolicy(Money discountAmount, DiscountCondition... conditions) {
super(conditions);
this.discountAmount = discountAmount;
}
@Override
protected Money getDiscountAmount(Screening screening) {
return discountAmount;
}
- Chúng ta nên trừu tượng hóa DiscountPolicy thành một giao diện và chia nó thành các triển khai của nó, NoneDiscountPolicy và DefaultDiscountPolicy đại diện cho các chính sách giảm giá chung.
- Chúng ta có thể nghĩ rằng việc thêm một giao diện riêng cho NoneDiscountPolicy sẽ làm tăng độ phức tạp mà không mang lại hiệu quả.
- Chúng ta cần phải nhận thức được rằng mọi thứ liên quan đến triển khai đều có thể là đối tượng của sự đánh đổi. Nói cách khác, mọi đoạn mã chúng ta viết đều phải có lý do chính đáng.
Tái sử dụng mã
- Kế thừa có thể được sử dụng để tái sử dụng mã.
- Tuy nhiên, tốt hơn là nên sử dụng hợp thành thay vì kế thừa để tái sử dụng mã.
- Hiện tại, Movie đang sử dụng hợp thành để tái sử dụng mã của DiscountPolicy.
- Nếu chúng ta đặt Movie làm lớp cha và chia nó thành AmountDiscountMovie và PercentDiscountMovie, thì đó sẽ là việc sử dụng kế thừa.
Kế thừa
- Nhược điểm của kế thừa
- Vi phạm đóng gói.
- Chúng ta cần phải hiểu rõ cấu trúc nội bộ của lớp cha.
- Xác suất lớp con cần thay đổi cùng với lớp cha là rất cao.
- Làm cho thiết kế kém linh hoạt hơn.
- Mối quan hệ giữa lớp cha và lớp con được xác định tại thời điểm biên dịch.
- Không thể thay đổi loại đối tượng tại thời điểm chạy.
- Tuy nhiên, hợp thành cho phép chúng ta thay thế instance tại thời điểm chạy thông qua các phương thức như chageDiscountPolicy() ở phía đối tượng sử dụng.
- Vi phạm đóng gói.
Hợp thành
- Phương thức tái sử dụng mã chỉ thông qua các tin nhắn được định nghĩa trong giao diện được gọi là hợp thành.
- Chúng ta có thể triển khai đóng gói và duy trì kết nối lỏng lẻo.
- Để đa hình, chúng ta cần phải kết hợp sử dụng kế thừa và hợp thành.
- Ví dụ, giao diện DiscountPolicy buộc phải sử dụng kế thừa để triển khai các thực thể con của nó.
Nguồn
- Đối tượng