[Tut 6 - Design Pattern] Factory

Factory Pattern là gì?

Factory Method là một mẫu khác thuộc nhóm các mẫu thiết kế phục vụ mục đích khởi tạo (kỳ trước chúng ta có mẫu Abstract Factory cũng nằm trong nhóm này). Điểm khác biệt cơ bản của 2 mẫu này đó là Abstract Factory dược dùng để tạo ra nhiều loại đối tượng thuộc cùng một nhóm, còn Factory Method nhằm mục đích thay đổi việc khởi tạo đổi tượng một cách linh hoạt.

Mình có một ví dụ đơn giản cho trường hợp này: Nhà bạn chỉ có một con thú cưng (giống cái nhé), và nó đang mang bầu, tới khi nó đẻ con, bạn chạy sang nhà hàng xóm khoe, nhưng người hàng xóm này chỉ mới chuyển tới thôi, và họ không biết con thú cưng của bạn là thuộc loài nào, nên họ chỉ có thể biết được ngay lúc bạn giới thiệu rằng: “Con thú cưng nhà nó đã đẻ con rồi đó”. Và một bà cụ nhà kế bên, khi nghe thấy bạn khoe sẽ nghĩ ngay rằng: "Thế là con mèo lúc trước mình cho nó đã đẻ ra mấy chú mèo con rồi!".

Qua ví dụ trên chúng ta có thể thấy cách để mẫu Factory Method được áp dụng: Bạn có thể giới thiệu rằng con thú cưng của bạn vừa đẻ con, nhưng chỉ với bấy nhiêu thông tin, người ta chỉ có thể biết rằng vừa có con thú cưng con ra đời, nhưng nếu bạn cho người ta biết con thú cưng đó là con chó, người ta sẽ biết chắc chắn là nó vừa sinh ra con chó con, còn nếu đó là con mèo, thì nó không thể sinh ra con gì khác ngoài con mèo con được (Ví dụ này chúng ta xem tất cả điều kiện là lý tưởng, không xét những trường hợp kinh dị như chó đẻ ra mèo).




Code ví dụ cho mẫu này sẽ bao gồm các lớp Pet, Dog, Cat đóng vai trò như các Product và ConcreteProduct, bạn (Me) chính là Creator trong mẫu, nếu bạn có một con chó, bạn sẽ là MeAndADog, và sẽ là MeAndACat nếu bạn có một con mèo, 2 lớp này sẽ đại diện cho ConcreteCreator.

Để đơn giản, chúng ta chỉ ban cho thú cưng của mình những gì mà ta muốn: sinh con (giveBirth) và kêu (talk).

Pet.java
public abstract class Pet {
 public abstract Pet giveBirth();
 public abstract void talk();
}

Cat.java
public class Cat extends Pet {

    @Override
    public Pet giveBirth() {
        return new Cat();
    }

    @Override
    public void talk() {
        System.out.println("Mew Mew");
    }
}

Dog.java
public class Dog extends Pet {

    @Override
    public Pet giveBirth() {
        return new Dog();
    }

    @Override
    public void talk() {
        System.out.println("Wolf Wolf");
    }
}

Bạn (Me và các lớp con) sẽ có thể chọn loại thú cưng của mình(getMyPet) và giới thiệu chúng (introduceMyPet).

Me.java
public abstract class Me {

    public abstract Pet getMyPet();

    public void introduceMyPet() {
        Pet myPet = getMyPet();
        System.out.println("The parent pet talks:");
        myPet.talk();
        System.out.println("It's giving birth !!!");
        Pet child = myPet.giveBirth();
        System.out.println("The new born pet talks:");
        child.talk();
    }
}

Ở đây bạn có thể thấy lớp cha này không xác định được con thú cưng của bạn thuộc loại nào, nó chỉ có thể định nghĩa cách bạn giới thiệu thú cưng của mình. Để biết được loại thú cưng, bạn cần định nghĩa với các lớp con của Me.

MeWithACat.java
public class MeWithACat extends Me {

    @Override
    public Pet getMyPet() {
        return new Cat();
    }
}

MeWithADog.java
public class MeWithADog extends Me {

    @Override
    public Pet getMyPet() {
        return new Dog();
    }
}

Và phần cuối cùng là xem chúng sẽ hoạt động với nhau như thế nào.

Main.java
public class Main {

    public static void main(String[] args) {
        System.out.println("once upon a time !!!");
        Me me = new MeWithACat();
        me.introduceMyPet();
        System.out.println();
        System.out.println("At present");
        me = new MeWithADog();
        me.introduceMyPet();
    }
}

Output:
once upon a time !!!
The parent pet talks:
Mew Mew
It's giving birth !!!
The new born pet talks:
Mew Mew

At present
The parent pet talks:
Wolf Wolf
It's giving birth !!!
The new born pet talks:
Wolf Wolf

Ví dụ 2:



Step 1

Tạo lớp interface.

Shape.java
public interface Shape {
 void draw();
}

Step 2

Tạo lớp implementing lớp interface vừa tạo.

Rectangle.java
public class Rectangle implements Shape {

 @Override
 public void draw() {
  System.out.println("Inside Rectangle::draw() method.");
 }
}

Square.java
public class Square implements Shape {

 @Override
 public void draw() {
  System.out.println("Inside Square::draw() method.");
 }
}

Circle.java
public class Circle implements Shape {

 @Override
 public void draw() {
  System.out.println("Inside Circle::draw() method.");
 }
}

Step 3

Tạo Factory class.

ShapeFactory.java
public class ShapeFactory {
//use getShape method to get object of type shape

    public Shape getShape(String shapeType) {
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        } else if (shapeType.equalsIgnoreCase("SQUARE")) {
            return new Square();
        }

        return null;
    }
}

Step 4

FactoryPatternDemo.java
public class FactoryPatternDemo {

    public static void main(String[] args) {
        ShapeFactory shapeFactory = new ShapeFactory();
//get an object of Circle and call its draw method.
        Shape shape1 = shapeFactory.getShape("CIRCLE");
//call draw method of Circle
        shape1.draw();
//get an object of Rectangle and call its draw method.
        Shape shape2 = shapeFactory.getShape("RECTANGLE");
//call draw method of Rectangle
        shape2.draw();
//get an object of Square and call its draw method.
        Shape shape3 = shapeFactory.getShape("SQUARE");
//call draw method of circle
        shape3.draw();
    }
}

Output
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.

Nhận xét

Bài đăng phổ biến từ blog này

Base64 image – Lợi hay hại?

Hàm "tap" trong Laravel Collection