Factory method, đầy đủ là Factory method pattern, là thiết kế mẫu hướng đối tượng trong việc thiết kế phần mềm cho máy tính, nhằm giải quyết vấn đề tạo một đối tượng mà không cần thiết chỉ ra một cách chính xác lớp nào sẽ được tạo. Factory method giải quyết vấn đề này bằng cách định nghĩa một phương thức cho việc tạo đối tượng, và các lớp con thừa kế có thể override để chỉ rõ đối tượng nào sẽ được tạo. Nói chung, "factory method" thường được áp dụng cho những phương thức mà nhiệm vụ chính của nó là tạo ra đối tượng.
Bản chất của mẫu thiết kế Factory là "Định nghĩa một giao diện (interface) cho việc tạo một đối tượng, nhưng để các lớp con quyết định lớp nào sẽ được tạo. "Factory method" giao việc khởi tạo một đối tượng cụ thể cho lớp con."
Cho dù động cơ của mẫu thiết kế "Factory method" là cho phép lớp con được chọn lựa kiểu đối tượng nào sẽ được tạo, việc sử dụng factory method cũng có những lợi ích khác. Bởi thế, việc thường xuyên sử dụng "factory method" không chỉ cho việc tạo đối tượng một cách đa dạng mà còn lợi dụng những lợi ích khác. Những hàm như thế thì thường là tĩnh.
Factory method gói gọn lại việc tạo đối tượng. Điều này hữu dụng nếu quá trình tạo phức tạp. Ví dụ như nó phụ thuộc vào những điều chỉnh trong tập tin cấu hình hay phụ thuộc vào thông tin của người dùng nhập vào.
Ví dụ một chương trình đọc tập tin ảnh và tạo ảnh thumbnail của nó. Chương trình hỗ trợ nhiều định dạng ảnh khác nhau, và mỗi định dạng ảnh sẽ có một lớp hỗ trợ việc đọc tập tin.
public interface ImageReader {
public DecodedImage getDecodedImage();
}
public class GifReader implements ImageReader {
public GifReader(InputStream in) {
// check that it's a gif, throw exception if it's not, then if it is
// decode it.
}
public DecodedImage getDecodedImage() {
return decodedImage;
}
}
public class JpegReader implements ImageReader {
//....
}
Mỗi khi chương trình đọc một ảnh, nó cần phải tạo một đối tượng phù hợp để đọc ảnh đó dựa vào những thông tin trong tập tin. Việc này có thể gói gọn trong factory method:
public class ImageReaderFactory {
public static ImageReader getImageReader(InputStream is) {
int imageType = figureOutImageType(is);
switch(imageType){
case ImageReaderFactory.GIF:
return new GifReader(is);
case ImageReaderFactory.JPEG:
return new JpegReader(is);
// etc.
}
}
}
Đoạn mã trong ví dụ bên trên sử dụng lệnh switch để chỉ định kết hợp một imageType
với một đối tượng factory cụ thể. Ngoài ra, có thể thay thế câu lệnh switch bằng cách sử dụng một mảng.
Có 3 giới hạn đối với việc sử dụng factory method. Một liên quan đến việc sửa đổi (tạm dịch từ refactoring) mã nguồn hiện tại; Hai vấn đề khác liên quan đến thừa kế.
Complex c = new Complex(-1, 0);
Những vấn đề trên có thể giải quyết bằng cách sử dụng ngôn ngữ lập trình (thay vì sử dụng mẫu thiết kế).
Pizza example:
public abstract class Pizza
{
public abstract decimal GetPrice();
public enum PizzaType
{
HamMushroom, Deluxe, Seafood
}
public static Pizza PizzaFactory(PizzaType pizzaType)
{
switch (pizzaType)
{
case PizzaType.HamMushroom:
return new HamAndMushroomPizza();
case PizzaType.Deluxe:
return new DeluxePizza();
case PizzaType.Seafood:
return new SeafoodPizza();
}
throw new System.NotSupportedException("The pizza type " + pizzaType.ToString() + " is not recognized.");
}
}
public class HamAndMushroomPizza: Pizza
{
private decimal price = 8.5M;
public override decimal GetPrice() { return price; }
}
public class DeluxePizza: Pizza
{
private decimal price = 10.5M;
public override decimal GetPrice() { return price; }
}
public class SeafoodPizza: Pizza
{
private decimal price = 11.5M;
public override decimal GetPrice() { return price; }
}
// Somewhere in the code
...
Console.WriteLine(Pizza.PizzaFactory(Pizza.PizzaType.Seafood).GetPrice().ToString("C2")); // $11.50
...
Pizza example:
//Our pizzas
function HamAndMushroomPizza(){
var price = 8.50;
this.getPrice = function(){
return price;
}
}
function DeluxePizza(){
var price = 10.50;
this.getPrice = function(){
return price;
}
}
function SeafoodPizza(){
var price = 11.50;
this.getPrice = function(){
return price;
}
}
//Pizza Factory
function PizzaFactory(){
this.createPizza = function(type){
switch(type){
case "Ham and Mushroom":
return new HamAndMushroomPizza();
case "DeluxePizza":
return new DeluxePizza();
case "Seafood Pizza":
return new SeafoodPizza();
default:
return new DeluxePizza();
}
}
}
//Sử dụng
var pizzaPrice = new PizzaFactory().createPizza("Ham and Mushroom").getPrice();
alert(pizzaPrice);