Tạo cả một gia đình

Trong thực tế chúng ta sẽ ít thấy và ít sử dụng đến design pattern này, tuy niên pattern này tương đối tiện khi chúng ta muốn đóng gói 1 họ các factory để tạo ra các đối tượng có chung 1 thể loại hay nằm trong cùng 1 chức năng.

Giới thiệu

Cũng giống như Factory pattern, tuy nhiên Abstract Factory pattern phức tạp hơn nhiều, nó sử dụng nhiều interface hơn cũng như nhiều lớp hơn.

Mục tiêu ra đời

Cung cấp giao diện để tạo một họ các đối tượng liên quan, mà không chỉ định rõ ràng các lớp của chúng.

Ví dụ

Chúng ta sẽ sử dụng ứng dụng quản lý sách làm ví dụ, và ở đây nhu cầu của chúng ta là tạo ra các đối tượng sách và đối tượng tác giả.

@Data
public abstract static class Book {

    private String name;

    public abstract String getCategory();
}

public static class HistoryBook extends Book {

    @Override
    public String getCategory() {
        return "history";
    }
}

public static class TechnologyBook extends Book {

    @Override
    public String getCategory() {
        return "technology";
    }
}

@Data
public abstract static class Author {

    private String name;

    public abstract String getMainCategory();
}

public static class HistoryAuthor extends Author {

    @Override
    public String getMainCategory() {
        return "history";
    }
}

public static class TechnologyAuthor extends Author {

    @Override
    public String getMainCategory() {
        return "technology";
    }
}

public interface AbstractFactory {

    <T> T newProduct(Class<T> type, String name);
}

public static class BookFactory implements AbstractFactory {

    @SuppressWarnings("unchecked")
    @Override
    public <T> T newProduct(Class<T> type, String name) {
        final Book book = type.equals(HistoryBook.class)
                    ? new HistoryBook()
                    : new TechnologyBook();
        book.setName(name);
        return (T) book;
    }
}

public static class AuthorFactory implements AbstractFactory {

    @SuppressWarnings("unchecked")
    @Override
    public <T> T newProduct(Class<T> type, String name) {
        final Author author = type.equals(HistoryAuthor.class)
                              ? new HistoryAuthor()
                              : new TechnologyAuthor();
        author.setName(name);
        return (T) author;
    }
}

public static class FactoryImpl implements AbstractFactory {

    private final AuthorFactory authorFactory = new AuthorFactory();
    private final BookFactory bookFactory = new BookFactory();

    @Override
    public <T> T newProduct(Class<T> type, String name) {
        return Book.class.isAssignableFrom(type)
            ? bookFactory.newProduct(type, name)
            : authorFactory.newProduct(type, name);
    }
}

Khi sử dụng sẽ thế này:

final AbstractFactory factory = new FactoryImpl();
final Book book = factory.newProduct(TechnologyBook.class, "EzyFox in Action");
final Author author = factory.newProduct(TechnologyAuthor.class, "Young Monkeys");

Chúng ta có thể thấy là mặc dù tạo ra các đối tượng khác nhau, nhưng cuối cùng cũng chỉ cần đến một giao diện duy nhất đó là AbstractFactory mà thôi.

Kết luận

Trong thực tế có lẽ sẽ ít khi dùng đến Abstract Factory pattern, như chúng ta thấy qua ví dụ, nó tương đối phức tạp với nhiều lớp và interface. Tuy nhiên trong một số trường hợp đặc biệt, nó lại rất có ích, đặc biệt là khi chúng ta cần đóng gói những thứ phức tạp và để người sử dụng phải quan tâm đến ít lớp trìu tượng nhất có thể.