한국어 | English | 日本語
Senior Web Application Developer (8.8+ years)
Tech & Dev
engineering
Focusing on web frontend and backend development

2. Factory 'Method' Pattern & 'Abstract' Factory Pattern

When developing software, you often encounter situations where you need to process 'different flows based on state.' For a single state, like a simple 'yes' or 'no,' an `if` statement is sufficient. For multiple states, `if-else` or `switch` statements can be used. However, if the logic corresponding to these 'different flows' becomes complex, an `if-else` block might easily exceed 100 lines of code. Does this truly promote reusability? Not only does such code become difficult to read, but it will undoubtedly contain repetitive logic within those many lines. A pattern is needed to cleanly separate 'varying logic' from 'common logic,' where the varying part either returns or creates different implementations based on the current state.
The process of returning an implementation based on a given state, where a function is the entity responsible for this return, is termed a Factory Method, and the corresponding design principle is the 'Factory Method Pattern.' Conversely, when the 'factory' responsibility is decoupled from the method itself, allowing the method to merely return a general category object, and the specific, state-dependent implementation is delegated to an Abstract Factory interface, this constitutes the 'Abstract Factory Pattern.' In essence, if a method orchestrates the state-dependent creation (factory logic), it's the Factory 'Method' Pattern; if an interface assumes this responsibility, it's the 'Abstract' Factory Pattern.

What is a ‘Factory’?

A factory, simply put, can be thought of as a vending machine. A ‘beverage’ vending machine will dispense ‘beverages,’ and a ‘snack’ vending machine will dispense ‘snacks.’ Since both the vending machine (VendingMachine) and the product (Product) are defined as interfaces, if you implement Product as a Beverage, then the VendingMachine should be implemented as a BeverageVendingMachine.

	VendingMachine machine;
	Product product;
	VendingMachine machine = new BeverageVendingMachine();
	Product product = machine.get();

A factory, as shown above, means implementing based on the situation.

What is a ‘Factory Method’?

A factory method, as the name suggests, is a method that acts as a factory, implementing based on the situation. It’s a function that returns a Product implementation depending on what kind of Product it is, corresponding to machine.get() in the example above.

Factory Method Pattern

The Factory Method Pattern involves defining a ‘factory method’ within an interface and then creating concrete ‘implemented factory methods’ that return situation-specific implementation objects for various situations. Let’s examine the benefits of using this pattern.

class VendingMachine {
	public Product get(String type) {
		if (type == "beverage") {
			return new Beverage();
		} else if (type == "snack") {
			return new Snack();
		}
	}
}
	VendingMachine machine = new VendingMachine();
	Product product = machine.get('beverage');
interface VendingMachine {
	public Product get();
}

class BeverageVendingMachine implements VendingMachine {
	public Product get() {
		return new Beverage();
	}
}

class SnackVendingMachine implements VendingMachine {
	public Product get() {
		return new Snack();
	}
}
	VendingMachine machine = new BeverageVendingMachine();
	Product product = machine.get();

Within the VendingMachine interface, you simply need to implement how the factory method will return a specific implementation according to the situation. An implementation class for a no-longer-used situation can simply be deleted, and if additional situation-specific handling is needed, you just create a new class.

Abstract Factory Pattern

Now, let’s assume the variety of beverages is steadily increasing. If we use the Factory Method Pattern, a new class would be created every time. Is this really optimal? No matter how many types of beverages emerge, the category ‘Beverage’ itself doesn’t change. Only the contents vary.

interface VendingMachine {
	public Product get();
}

class FruitBeverageVendingMachine implements VendingMachine {
	public Product get() {
		return new FruitBeverage();
	}
}

class SparklingBeverageVendingMachine implements VendingMachine {
	public Product get() {
		return new SparklingBeverage();
	}
}

class TeaBeverageVendingMachine implements VendingMachine {
	public Product get() {
		return new TeaBeverage();
	}
}

...

FruitBeverage, SparklingBeverage, and TeaBeverage are all included in the ‘Beverage’ category, and in reality, the logic within these three internal classes would have only minor differences; most would be the same. If we create a generic Beverage class, we would only need to change the ingredients inside it. This solves the duplication problem of proliferating ...Beverage classes as follows:

interface VendingMachine {
	Maker maker;
	public Product get() {
		return new Beverage(maker);
	}
}

class FruitBeverageVendingMachine implements VendingMachine {
	Maker maker = new FruitBeverageMaker();
}

class SparklingBeverageVendingMachine implements VendingMachine {
	Maker maker = new SparklingBeverageMaker();
}

class TeaBeverageVendingMachine implements VendingMachine {
	Maker maker = new TeaBeverageMaker();
}

...

While the ‘Factory Method Pattern’ has a factory “method” that returns situation-specific implementation objects, the ‘Abstract Factory Pattern’ has a method that simply returns a category object, and situation-specific detailed implementation is delegated to an “abstract” factory interface.

So, isn’t proliferating ...Beverage classes effectively the same as proliferating ...BeverageMaker classes? Yes, it’s effectively the same. But why is the responsibility for situation-specific implementation delegated to the abstract factory interface?

This is to allow VendingMachine to have only the role of providing products, while BeverageMaker shares the responsibility for product production.

2. Factory 'Method' Pattern & 'Abstract' Factory Pattern
Author
Aaron
Posted on
Licensed Under
CC BY-NC-SA 4.0
CC BY-NC-SA 4.0
More in this category
Recent posts
The Erosion of Conversational Muscle and Communication Styles by LLM Filters
In an era where LLM tools, which filter out conversational impoliteness and deliver refined responses, have become commonplace, are we truly engaging in more thoughtful conversations? This article examines the phenomenon of conversational ability, which should be honed through countless failures in real-time communication, degenerating due to reliance on external tools. It further explores the potential societal anxieties and shifts in generational behavioral patterns that this trend may bring.
Optimal Timing and Strategy for Salary Negotiation with Senior Candidates
Salary negotiation is more than just an exchange of figures; it's a strategic dance of psychological timing. This analysis explores why engaging in a gradual negotiation process from the initial stages of recruitment, rather than waiting until after a final offer (when candidates tend to adopt a more calculative stance), proves more efficient for companies and fosters a more honest sharing of resources.
The Limits of the Rule of Law and Human Diversity
The belief that all human actions can be regulated by a single legal system may be an act of hubris. This article offers a sharp analysis of the paradox of the rule of law faced by humanity, which, having escaped the hierarchical controls of the Middle Ages, has now embraced infinite modern freedom. It further examines the deepening social coercion and the demonization of others that arise under the guise of diversity.
토스트 예시 메세지