Thứ Năm, 27 tháng 12, 2018

Abstract Factory Pattern

Nếu bạn đã được đọc về Factory Method Pattern, thì mình nghĩ Abstract Factory Pattern chỉ là 1 cái trường hợp đặc biệt của Factory Method Pattern mà thôi.
Abstract Factory Pattern: cung cấp 1 interface cho phép người dùng tạo ra 1 nhóm các đối tượng độc lập hoặc có liên hệ với nhau mà không cần quan tâm tới lớp thực thi của chúng
Nghe có vẻ bù cả đầu đúng không? Nhưng mà sự thật thì cực kì đơn giản.
Quay lại với ví dụ trong bài Factory Method Pattern, chúng ta có cái game phi thuyền bắn súng đấy. Bạn để ý nhé, trong game lúc nào cũng có background (tức là cái hình nền ấy) nó xuất hiện khác nhau với mỗi level. Ví dụ với level 1, mục tiêu là bắn các mảnh thiên thạch thì background sẽ là bầu trời đêm chẳng hạn. Level 2 bắn phá các phi thuyền thì background sẽ là các linh kiện máy móc... vân vân và mây mây. Và tất nhiên, không phải background của chúng ta là random được, nó phải có lý với bối cảnh của enemy. Không phải tự dưng enemy là các mảnh thiên thạch, mà background lại là đồng cỏ được, nó không có phù hợp gì hết. Hay là enemy là mấy con bò, mà background lại là trên dải ngân hà, đúng lafk hông hợp lý. Vậy nên, ứng với mỗi enemy, chúng ta phải có 1 background đi kèm. Vậy để làm được thế thì ta không thể tạo 2 cái Factory riêng biệt cho enemy và background được. Vì có thể, trong tương lai, không những chỉ có background mà có thể có các hiệu ứng mây mưa, sương khói các thứ cũng phải làm sao cho hợp lý. Như vậy sẽ dẫn tới chúng ta có vô vàn Factory riêng lẻ. Và Abstract Factory Pattern lúc này mới được đưa vào sử dụng.
Cùng xem lại mô hình củ Factory Method Pattern nhé.
Ta thấy, mỗi factory sẽ tạo cho chúng ta 1 đối tượng là IProduct. Nhưng ở bài toán hiện tại, chúng ta không chỉ có 1 product (là enemy) nữa, mà chúng ta có đến 2, hoặc 3 đối tượng cơ. Vậy nên, Abstract Factory Pattern cải tiến lại, giúp cho Factory có thể cho ra được 2 nhiều hơn 1 product.
Ví dụ ta có 2 interface IProductEnemy và IProductBackground, mô hình cảu Abstract Factory Pattern sẽ như sau:
Ta thấy, bây h factory của chúng ta đã có thể cho ra 2 product. Và tất nhiên, khi hiện thực IFactory, thì chúng ta cũng đã định nghĩa được những background nào nên đi kèm với enemy nào rồi, nên sẽ ko có hiện tượng bất hợp lý ở UI khi người ta chơi game cả. Vậy thôi, đó là Abstract Factory Pattern.
Bây h thử code vài dòng để hiểu hơn nó là như thế nào nà. Đầu tiên vẫn như cũ, ta tạo interface của enemy và các hiện thực của nó.
public interface Enemy{
    public void speed();
    public void healthy();
} 
public interface FirstLevelEnemy extends Enemy{
} 
public interface SecondLevelEnemy extends Enemy{
}
public class BigMeteorite implements FirstLevelEmemy {
   public void speed() {
       //lam cai gi do
   }
    public void healthy(){
       //lam cai gi do
   }
}
public class VietNamSpaceShip implements SecondLevelEnemy {
   public void speed() {
       //lam cai gi do
   }
    public void healthy(){
       //lam cai gi do
   }
}
Bây giờ chúng ta tạo ra interface cho background và các hiện thực của nó.
public interface Background{
    public void display();
} 
public interface FirstLevelBackground extends Background{
} 
public interface SecondLevelBackground extends Background{
}
public class DarkGalaxy implements FirstLevelBackground {
   public void display() {
       //lam cai gi do
   }   
}
public class OldShipFLoor implements SecondLevelBackground {
   public void display() {
       //lam cai gi do
   } 
}
Tiếp đến ta tạo ra interface Factory và các hiện thực của nó.
public interface IFactory{
    public Enemy createEnemy();
    public Background createBackground();
} 
public class FirstLevelFactory implements IFactory {
    public Enemy createEnemy() {
       return RandomEnemy();
    }
    public Background createBackground() {
       return RandomEnemy();
    }  
    private FirstLevelEnemy RandomEnemy() {
       //lam gi do de random cac kieu
    }
    private FirstLevelBackground RandomBackground() {
       //lam gi do de random cac kieu
    }
}
public class SecondLevelFactory implements IFactory {
    public Enemy createEnemy() {
       return RandomEnemy();
    } 
    public Background createBackground() {
       return RandomEnemy();
    }  
    private SecondLevelEnemy RandomEnemy() {
       //lam gi do de random cac kieu
    }
    private SecondLevelBackground RandomBackground() {
       //lam gi do de random cac kieu
    }
}
Và cuối cùng là thêm 1 lớp factory bên ngoài IFactory được nữa. Ví dụ:
public class MotherOfFactory {
     public static IFactory createFactory(int level) {
         switch (level) {
             case 1: return FirstLevelFactory(); break;  
             case 2: return SecondLevelFactory(); break;  
             //and so on 
         }
     }
}
Bây giờ giả sử bạn ở level 1, thì có thể khởi tạo enemy bằng cách.
Enemy enemy = MotherOfFactory.createFactory(1).createEnemy();
Nếu bây giờ, bạn muốn lấy background, thì chỉ cần:
Background background = MotherOfFactory.createFactory(1).createBackground();
Lúc này Background và Enemy của bạn sẽ rất hợp lý, vì bạn đã định nghĩa nó ngay trong hiện thực của IFactory rồi.
Vậy thôi, quá đơn giản phải không?
Share:

0 nhận xét:

Đăng nhận xét

Được tạo bởi Blogger.