Skip to main content

Factory method – Wikipedia tiếng Việt


Mô tả Factory method bằng UML

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."



  • "Factory method" thường được dùng trong bộ phát triển (toolkit) hay framework, ở đó, đoạn mã của framework cần thiết phải tạo một đối tượng là những lớp con của ứng dụng sử dụng framework đó.

Những lợi ích khác và biến thể[sửa | sửa mã nguồn]


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.


Tóm lược[sửa | sửa mã nguồn]


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.


 1 public interface ImageReader {
2 public DecodedImage getDecodedImage();
3 }
4
5 public class GifReader implements ImageReader {
6
7 public GifReader(InputStream in) {
8 // check that it's a gif, throw exception if it's not, then if it is
9 // decode it.
10 }
11
12 public DecodedImage getDecodedImage() {
13 return decodedImage;
14 }
15 }
16
17 public class JpegReader implements ImageReader {
18 //....
19 }

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:


 1 public class ImageReaderFactory {
2
3 public static ImageReader getImageReader(InputStream is) {
4
5 int imageType = figureOutImageType(is);
6
7 switch(imageType){
8 case ImageReaderFactory.GIF:
9 return new GifReader(is);
10 case ImageReaderFactory.JPEG:
11 return new JpegReader(is);
12 // etc.
13 }
14 }
15 }

Đ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ế.


  • Giới hạn đầu tiên là việc sửa đổi (refactoring) một lớp đã có sẵn để sử dụng factory sẽ làm hỏng ứng dụng. Ví dụ, nếu lớp Complex là một lớp chuẩn, có thể tồn tại nhiều đoạn mã sử dụng lớp này như sau:
Complex c = new Complex(-1, 0);

Một khi chúng ta thấy cần thiết phải có hai factory khác nhau, chúng ta thay đổi lớp này. Tuy nhiên, vì hàm khởi tạo (constructor) bây giờ trở thành private, đoạn mã này sẽ không được dịch nữa.
  • Giới hạn thứ hai là do mẫu thiết kế này dựa vào việc sử dụng hàm khởi tạo private, lớp này sẽ không thể được thừa kế và mở rộng. Các lớp con phải thừa kế hàm khởi tạo của lớp cha, nhưng việc này không thực hiện được vì hàm khởi tạo là private.

  • Giới hạn thứ ba là, nếu chúng ta mở rộng một lớp (ví dụ: tạo một hàm khởi tạo protected -- điều này nguy hiểm nhưng chấp nhận được), lớp con phải cung cấp lại tất cả các hàm factory với tất cả thông số phải chính xác (bao gồm tên hàm và tham số). Ví dụ, nếu lớp StrangeComplex thừa kế lớp Complex, trừ khi StrangeComplex cung cấp tất cả các hàm factory, nếu không việc gọi

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ế).



C#[sửa | sửa mã nguồn]


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
...

JavaScript[sửa | sửa mã nguồn]


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);




  • Fowler, Martin; Kent Beck, John Brant, William Opdyke, and Don Roberts (tháng 6 năm 1999). Refactoring: Improving the Design of Existing Code. Addison-Wesley. ISBN 0-201-48567-2. 

  • Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. ISBN 0-201-63361-2. 

  • Cohen, Tal; Gil, Joseph (2007). “Better Construction with Factories” (PDF). Journal of Object Technology (Bertrand Meyer). Truy cập ngày 12 tháng 3 năm 2007. 

Bản mẫu:Design Patterns Patterns






Comments

Popular posts from this blog

Reuben Chapman - Wikipedia

Reuben Chapman Thống đốc thứ 13 của Alabama Tại văn phòng 16 tháng 12 năm 1847 - 17 tháng 12 năm 1849 Trước đó là Joshua L. 19659006] Thành công bởi Henry W. Collier Thành viên của Hoa Kỳ Hạ viện từ quận 6 của Alabama Tại văn phòng Ngày 4 tháng 3 năm 1843 - 3 tháng 3 năm 1847 Trước đó là Quận không hoạt động ] Williamson Robert Winfield Cobb Thành viên của Hoa Kỳ Hạ viện từ quận lớn của Alabama Tại văn phòng 4 tháng 3 năm 1841 - 3 tháng 3 năm 1843 Trước đó là Quận không hoạt động Quận không hoạt động Thành viên của Hoa Kỳ Hạ viện từ quận 1 của Alabama Tại văn phòng Ngày 4 tháng 3 năm 1835 - ngày 3 tháng 3 năm 1841 Trước Clement Comer Clay Thành công bởi không hoạt động Thông tin cá nhân Sinh ( 1799-07-15 ) ngày 15 tháng 7 năm 1799 17, 1882 (1882-05-17) (ở tuổi 82) Huntsville, Alabama, Mỹ - 17 tháng 5 năm 1882) là một luật sư và chính trị gia người Mỹ. Sinh ngày 15 tháng 7 năm 1799 tại Bowling Green, Virginia, ông chuyển đến Alabama vào...

Maurice Halbwachs - Wikipedia

Maurice Halbwachs ( Tiếng Pháp: [mɔˈʁis ˈalbvaks] ; 11 tháng 3 năm 1877 - 16 tháng 3 năm 1945) là một nhà triết học và xã hội học người Pháp nổi tiếng vì đã phát triển khái niệm về ký ức tập thể. Đời sống và giáo dục sớm [ chỉnh sửa ] Sinh ra ở Reims, Pháp, Halbwachs đã tham dự École Normale Supérieure ở Paris. Ở đó, ông học triết học với Henri Bergson, người có ảnh hưởng lớn đến suy nghĩ của ông. Ông đã tổng hợp trong Triết học vào năm 1901. Ông đã giảng dạy tại nhiều lycées trước khi đến Đức vào năm 1904, nơi ông học tại Đại học Gottingen và làm việc trên danh mục các bài báo của Leibniz. Ông được đề cử đồng biên tập một phiên bản tác phẩm của Leibniz mà không bao giờ thành hiện thực. Ông trở lại Pháp vào năm 1905 và gặp Émile Durkheim, người đã khơi dậy mối quan tâm của ông đối với xã hội học. Ông sớm gia nhập ban biên tập của Lnnnn Sociologique nơi ông làm việc với François Simiand chỉnh sửa các phần Kinh tế và Thống kê. Năm 1909, ông trở về Đức để học chủ nghĩa M...

Olin J. Eggen - Wikipedia

Olin Jeuck Eggen (9/7/1919 - 2/10/1998) là một nhà thiên văn học người Mỹ. Tiểu sử [ chỉnh sửa ] Olin Jeuck Eggen được sinh ra cho Olin Eggen và Bertha Clare Jeuck tại làng Orfordville ở Rock County, Wisconsin. Cả hai cha mẹ anh đều là người Na Uy. Ông tốt nghiệp Đại học Wisconsin Wisconsin Madison năm 1940. Sau khi phục vụ trong Thế chiến II trong OSS, ông trở lại trường đại học và nhận bằng tiến sĩ. trong vật lý thiên văn năm 1948. Ông được biết đến như một trong những nhà thiên văn học quan sát giỏi nhất thời bấy giờ. Ông được biết đến nhiều nhất với bài báo năm 1962 với Donald Lynden-Bell và Allan Sandage, lần đầu tiên đề xuất rằng Dải Ngân hà đã sụp đổ khỏi đám mây khí. Đầu tiên, ông đưa ra khái niệm được chấp nhận hiện nay về các nhóm sao di chuyển. Ông đã giành được Bài giảng Henry Norris Russell vào năm 1985. Trong thời gian đó, ông giữ các vị trí tại Đài thiên văn Lick (1948 ví1956), Đài thiên văn Hoàng gia Greenwich (1956 mật1961), Viện Công nghệ California, Mt. Đà...