Design Pattern | Abstract Factory Methods

What Is the Abstract Factory Pattern?

  • Abstract Factory means an abstract factory.
  • Being abstract means focusing only on the interface without considering how it is concretely implemented.
  • The Abstract Factory pattern focuses on interfaces rather than the concrete implementation of parts. It assembles parts using only those interfaces and organizes them into products.
  • It creates products by combining related parts.
  • In GoF design patterns, it is classified as a creational design pattern.

Abstract Factory Pattern Example Program

This example program outputs a favorites list in HTML format.

Class Diagram
Abstract Factory Pattern Class Diagram

1. Factory Class

This class represents an abstract factory. It creates Link, Tray, and Page.

Factory.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

public abstract class Factory {

    public abstract Link createLink(String caption, String url);

    public abstract Tray createTray(String caption);

    public abstract Page createPage(String title);

    public static Factory getFactory(String classname) {
        Factory factory = null;
        try {
            factory = (Factory) Class.forName(classname).getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            System.err.println("클래스 " + classname + "를 찾을 수 없습니다.");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factory;
    }
}

2. Item Class

This class treats Link and Tray uniformly.

Item.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

public abstract class Item {
    protected String caption;

    public Item(String caption) {
        this.caption = caption;
    }

    public abstract String makeHTML();
}

Abstract part: a class that represents an HTML link.

Link.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

public abstract class Link extends Item {
    protected String url;

    public Link(String caption, String url) {
        super(caption);
        this.url = url;
    }
}

4. Tray Class

Abstract part: a class that collects Link and Tray.

Tray.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

import java.util.ArrayList;

public abstract class Tray extends Item {
    protected ArrayList tray = new ArrayList();

    public Tray(String caption) {
        super(caption);
    }

    public void add(Item item) {
        tray.add(item);
    }
}

5. Page Class

Abstract part: a class that represents an HTML page.

Page.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;

public abstract class Page {
    protected String title;
    protected ArrayList content = new ArrayList();

    public Page(String title) {
        this.title = title;
    }

    public void add(Item item) {
        content.add(item);
    }

    public void output() {
        try {
            String filename = title + ".html";
            Writer writer = new FileWriter(filename);
            writer.write(this.makeHTML());
            writer.close();
            System.out.println(filename + "을 생성했습니다.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public abstract String makeHTML();
}

6. ListFactory Class

This class represents a concrete factory. It creates ListLink, ListTray, and ListPage.

ListFactory.java

package com.devkuma.designpattern.creational.abstractfactory.listfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Factory;
import com.devkuma.designpattern.creational.abstractfactory.factory.Link;
import com.devkuma.designpattern.creational.abstractfactory.factory.Page;
import com.devkuma.designpattern.creational.abstractfactory.factory.Tray;

public class ListFactory extends Factory {
    public Link createLink(String caption, String url) {
        return new ListLink(caption, url);
    }

    public Tray createTray(String caption) {
        return new ListTray(caption);
    }

    public Page createPage(String title) {
        return new ListPage(title);
    }
}

Concrete part: a class that represents an HTML link.

ListLink.java

package com.devkuma.designpattern.creational.abstractfactory.listfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Link;

public class ListLink extends Link {
    public ListLink(String caption, String url) {
        super(caption, url);
    }

    public String makeHTML() {
        return "  <li><a href=\"" + url + "\">" + caption + "</a></li>\n";
    }
}

8. ListTray Class

Concrete part: a class that collects Link and Tray.

ListTray.java

package com.devkuma.designpattern.creational.abstractfactory.listfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Item;
import com.devkuma.designpattern.creational.abstractfactory.factory.Tray;

import java.util.Iterator;

public class ListTray extends Tray {
    public ListTray(String caption) {
        super(caption);
    }

    public String makeHTML() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<li>\n");
        buffer.append(caption + "\n");
        buffer.append("<ul>\n");
        Iterator it = tray.iterator();
        while (it.hasNext()) {
            Item item = (Item) it.next();
            buffer.append(item.makeHTML());
        }
        buffer.append("</ul>\n");
        buffer.append("</li>\n");
        return buffer.toString();
    }
}

9. ListPage Class

Concrete part: a class that represents an HTML page.

ListPage.java

package com.devkuma.designpattern.creational.abstractfactory.listfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Item;
import com.devkuma.designpattern.creational.abstractfactory.factory.Page;

import java.util.Iterator;

public class ListPage extends Page {
    public ListPage(String title) {
        super(title);
    }

    public String makeHTML() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<html><head><title>" + title + "</title></head>\n");
        buffer.append("<body>\n");
        buffer.append("<h1>" + title + "</h1>\n");
        buffer.append("<ul>\n");
        Iterator it = content.iterator();
        while (it.hasNext()) {
            Item item = (Item) it.next();
            buffer.append(item.makeHTML());
        }
        buffer.append("</ul>\n");
        buffer.append("</body></html>\n");
        return buffer.toString();
    }
}

10. Main Class

This is the class that executes the main processing.

Main.java

package com.devkuma.designpattern.creational.abstractfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Factory;
import com.devkuma.designpattern.creational.abstractfactory.factory.Link;
import com.devkuma.designpattern.creational.abstractfactory.factory.Page;
import com.devkuma.designpattern.creational.abstractfactory.factory.Tray;

public class Main {
    public static void main(String[] args) {

        Factory factory = Factory.getFactory("com.devkuma.designpattern.creational.abstractfactory.listfactory.ListFactory");

        Link devkuma = factory.createLink("Devkuma", "https://www.devkuma.com//");
        Link araikuma = factory.createLink("araikuma", "https://araikuma.tistory.com/");

        Link naver = factory.createLink("Naver", "https://www.naver.com/");
        Link daum = factory.createLink("Daum", "https://www.daum.com/");
        Link google = factory.createLink("Google", "https://www.google.com/");

        Tray pgTray = factory.createTray("프로그래밍");
        pgTray.add(devkuma);
        pgTray.add(araikuma);

        Tray searchTray = factory.createTray("검색사이트");
        searchTray.add(naver);
        searchTray.add(daum);
        searchTray.add(google);

        Page page = factory.createPage("즐겨찾기");
        page.add(pgTray);
        page.add(searchTray);
        page.output();
    }
}

11. Execution Result

The file generated by the program is shown below.

즐겨찾기.html

<html><head><title>즐겨찾기</title></head>
<body>
<h1>즐겨찾기</h1>
<ul>
<li>
프로그래밍
<ul>
  <li><a href="https://www.devkuma.com//">Devkuma</a></li>
  <li><a href="https://araikuma.tistory.com/">araikuma</a></li>
</ul>
</li>
<li>
검색사이트
<ul>
  <li><a href="https://www.naver.com/">Naver</a></li>
  <li><a href="https://www.daum.com/">Daum</a></li>
  <li><a href="https://www.google.com/">Google</a></li>
</ul>
</li>
</ul>
</body></html>

Advantages of the Abstract Factory Pattern

For example, when adding a new concrete factory to the example program, you create subclasses of Factory, Link, Tray, and Page and implement each abstract method.
In other words, you only concretize the abstract parts held by the classes in the factory package. At this time, no matter how many concrete factories are added, there is no need to modify the abstract factory.