Định nghĩa
Định nghĩa giao diện cho việc khởi tạo một đối tượng, nhưng để lớp
con quyết định lớp nào sẽ được khởi tạo. Factory Method Factory Method
giao việc khởi tạo một đối tượng cụ thể cho lớp con.
Định nghĩa một hàm tạo ảo.
Toán tử new không dùng trong trường hợp này.
Vấn đề
Một framework cần
làm chuẩn hóa mô hình kiến trúc cho nhiều ứng dụng, nhưng cho phép các ứng dụng
riêng biệt định nghĩa các đối tượng của nó và cung cấp khởi tạo cho chúng.
Thảo luận
- Factory Method tạo ra các đối
tượng như là Template Method để cài đặt các thuật toán theo ý muốn. Class cha sẽ
chỉ rõ tất cả các chuẩn và cách xử lý chung (sử dụng các hàm ảo là
“placeholders” – phần giữ chỗ cho các bước khởi tạo), sau đó ủy nhiệm, giao phú
việc tạo chi tiết cho các lớp con được cung cấp bởi client.
- Factory Method tạo các thiết kế
có thể dễ dàng chỉnh sửa và có ít độ phức tạp. Các design pattern khác yêu cầu
các class mới, riêng Factory Method chỉ yêu cầu một operation(thao tác, hoạt động)
mới.
- Mọi người thường sử dung
Factory Method như một chuẩn để tạo ra các đối tượng; thức sự nó không cần thiết
nếu: Việc khởi tạo của class đó không thay đổi, hoặc việc khởi tạo đặt ở trong
một operation mà class con có thể dễ dàng ghi đè lên(như khởi tạo một
operation).
- Factory Method tương tự như
Abstract Factory nhưng không nhấn mạnh việc tạo các đối tượng cùng một họ.
- Các Factory Mothod thường được
xác định bởi một khung kiến trúc, sau đó được thực thi bởi người dùng của khung
đó.
Cấu trúc
Việc áp dụng cài đặt Factory
Method được thảo luận trong Gang of Four (bên dưới) phần lớn giống với Abstract
Factory. Vì thế, các trình bày trong bài này này chủ yếu tập trung vào phương
pháp tiếp cận đã trở nên phổ biến từ trước.
Một định nghĩa ngày càng phổ biến
của Factory Method là: một phương thức static của class trả về một đối tượng của
kiểu class. Không giống như constructor(hàm tạo), đối tượng thực sự trả về có
thể là một thể hiện của lớp con. Cũng không giống như constructor, một đối tượng
tồn tại có thể sử dụng lại, thay vì phải khởi tạo một đối tượng mới. Và cũng
không giống như constructor, Factory Method có thể có nhiều tên, mô tả khác
nhau.
Ví dụ:
Color.make_RGB_color(float red, float green, float blue)
và
Color.make_HSB_color(float hue, float saturation, float brightness)
Client hoàn toàn tách rời từ
các cài đặt chi tiết của lớp thừa kế. Đa hình việc khởi tạo là có thể.
Ví dụ
Factory Method định nghĩa một
giao diện cho việc khởi tạo đối tượng, nhưng để lớp con quyết định lớp nào được
khởi tạo. Máy khuôn ép nhựa mô tả pattern này. Các nhà sản xuất đồ chơi bằng nhựa
xử lý bột nhựa và đưa chúng vào khuôn có hình dạng mong muốn. Lớp của đồ chơi
(ô tô,… ) được xác định bởi khuôn đó.
Kiểm tra
Nếu bạn có một hệ thống phân cấp thừa kế trong các đa hình, xem
xét thêm khả năng tạo đa hình bằng cách định nghĩa một static factory me thod
trong lớp cơ sở.
Thiết các đối số cho factory method. Những phẩm chất hoặc đặc
tính nào cần và đủ để xác định chính xác lớp thừa kế.
Xem xét việc thiết kế một “object pool” nội bộ để cho phép các đối
tượng được tái sử dụng thay vì tạo lại từ đầu
Xem xét việc đặt các hàm tạo là private hoặc protected.
Kinh nghiệm
- Các lớp Abstract Factory có thể cài đặt với Factory Methods,
nhưng cũng có thể cài đặt với Prototype.
- Các Factory Method thường được gọi bên trong các Template Method
- Factory Method: tạo thông qua thừa kế. Prototype: tạo thông qua ủy
quyền.
- Thông thường, việc thiết kế bắt đầu với Factory Method (ít phức
tạp, nhiều tùy biến, cài thiện, các lớp con nhiều) và tiến hóa thành Abstract
Factory, Prototype, hoặc Builder (tính mềm dẻo, sự phức tạp hơn) khi các lập
trình viên nhận ra rằng tính mềm dẻo là cần thiết.
- Prototype không yêu cầu lớp con, nhưng nó yêu cầu một toán tử khởi
tạo. Factory Method yêu cầu lớp con, nhưng không yêu cầu khởi tạo.
- Ưu điểm của Factory Method là có thể trả về cùng một đối tượng
nhiều lần, hoặc có thể trả về một lớp con hơn là một đối tượng có kiểu chính
xác.
- Chủ trương của Factory Method thì đây là vấn đề chính của ngôn
ngữ thiết kế(khuyết điểm) rằng tất cả các hàm tạo phải để là private hoặc
protected. Đó là công việc không ai khác là lớp sản xuất tạo ra một đối tượng mới
hoặc tái sử dụng lại đối tượng cũ.
- Toán tử new thì thực sự gây nguy hại. Có sự khác nhau giữa yêu cầu
một đối tượng hoặc khởi tạo nó. Toán tử new luôn luôn tạo đối tượng và
không đóng gói đối tượng khởi tạo. Factory Method đảm bảo việc thực hiện đóng
gói đó, và cho phép một đối tượng được yêu cầu mà không cần có sự liên kết với
hành động được tạo ra.
Ví dụ cài đặt thực hiện Factory Design Pattern trong Java
Trong lập trình hướng đối tượng, factory method là mẫu khởi tạo sử dụng factoy method để giải quyết vấn
đề tạo ra các đối tượng mà không cần phải xác định chính xác lớp của đối tượng
được tạo ra. Điều này được thực hiện bằng việc tạo ra các đối tượng thông qua
việc gọi một phương thức factory method hoặc được xác định trong một interface và thực hiện bởi các lớp con, hoặc thực hiện trong lớp cơ sở và được ghi đè bởi
lớp dẫn xuất thay vì bằng cách gọi một constructor.
interface ImageReader {
DecodedImage getDecodeImage();
}
class DecodedImage {
private String image;
public DecodedImage(String image) {
this.image = image;
}
@Override public String toString() {
return image + ": is decoded";
}
}
class GifReader implements ImageReader {
private DecodedImage decodedImage;
public GifReader(String image) {
this.decodedImage = new DecodedImage(image);
}
@Override public DecodedImage getDecodeImage() {
return decodedImage;
}
}
class JpegReader implements ImageReader {
private DecodedImage decodedImage;
public JpegReader(String image) {
decodedImage = new DecodedImage(image);
}
@Override public DecodedImage getDecodeImage() {
return decodedImage;
}
}
public class FactoryMethodDemo {
public static void main(String[] args) {
DecodedImage decodedImage;
ImageReader reader = null;
String image = args[0];
String format = image.substring(image.indexOf('.') + 1, (image.length()));
if (format.equals("gif")) {
reader = new GifReader(image);
}
if (format.equals("jpeg")) {
reader = new JpegReader(image);
}
assert reader != null;
decodedImage = reader.getDecodeImage();
System.out.println(decodedImage);
}
}
إرسال تعليق