☁️ Template Method
메서드를 템플릿화 하는 패턴이다. abstract 클래스로 선언하여 구현 메서드에 템플릿 로직을 생성한다. 템플릿 로직에서 동작할 특정 동작은 abstract 메서드로 선언하여 이를 확장하는 클래스에게 행동을 위임한다.
// AbstractClass
abstract class CoffeeTemplate {
final void makeCoffee() {
boilWater();
brewCoffeeGrounds();
pourInCup();
addCondiments();
System.out.println("Coffee is ready!");
}
abstract void boilWater();
abstract void brewCoffeeGrounds();
abstract void pourInCup();
abstract void addCondiments();
}
// ConcreteClass
class CoffeeWithHook extends CoffeeTemplate {
@Override
void boilWater() {
System.out.println("Boiling water");
}
@Override
void brewCoffeeGrounds() {
System.out.println("Brewing coffee grounds");
}
@Override
void pourInCup() {
System.out.println("Pouring coffee into cup");
}
@Override
void addCondiments() {
System.out.println("Adding sugar and milk");
}
}
public class TemplateMethodPatternExample {
public static void main(String[] args) {
CoffeeTemplate coffee = new CoffeeWithHook();
coffee.makeCoffee();
}
}
이렇게 커피를 만드는 전체 방식은 템플릿화 해놓고 실질적인 행동은 하위 클래스에서 선언하도록 하여, 결과적으로 CoffeTemplate의 makeCoffee 메서드를 통해 라떼, 아메리카노, 등등의 모든 커피를 생성할 수 있는 다형성을 제공하는 패턴이다.
스프링에서는?
스프링에서 Template Method 패턴은 DispatcherServlet에서 사용되고 있다. 일부 코드만을 살펴보면
DispatcherServlet
은 FrameworkServlet
을 FrameworkServlet
은 HttpServletBean
을 확장한다.
public abstract class FrameworkServlet
extends HttpServletBean implements ApplicationContextAware {
// 템플릿 메서드
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
try {
// doService의 선언을 하위 클래스로 위임
this.doService(request, response);
} catch (IOException | ServletException var16) {
// ...
}
// doService의 선언을 하위 클래스로 위임
protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
FrameworkServlet에서 선언한 템플릿에 맞추어 DispatcherServlet은 doService 메서드를 재정의하여 사용한다.
Template Method 패턴이란 로직을 처리하는 구조를 상위 클래스에 양식처럼 저장해놓고 로직을 수행하는 내부동작을 하위 클래스에서 재정의하게 함으로써 로직 처리 구조를 변경하지 않고 동작을 재정의하는 패턴이다.
구조를 변경하지 않은 상태로 확장함으로써 하위 클래스의 결과에 대한 일관성을 얻을 수 있고, 중복 코드가 줄어든다. 클라이언트에서는 추상화를 의존하게 되어 DIP, OCP를 만족하는 설계가 된다. 결국 변경에 유연하고 확장에 용이한 설계가 된다는 것이다.
☁️ Factory Method
Factory method 는 객체 생성과 반환의 책임을 하위 클래스에게 위임하는 패턴이다.
// 동물 인터페이스
interface Animal {
void makeSound();
}
// 팩터리 메서드를 가지고 있는 동물 팩터리 인터페이스
interface AnimalFactory {
Animal createAnimal();
}
// 각 동물의 구체적인 구현 클래스들
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
// 각 동물에 대한 팩터리 메서드를 가지고 있는 구현 클래스들
class DogFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
class CatFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
}
public class FactoryMethodPatternExample {
public static void main(String[] args) {
// Dog를 생성하는 팩터리를 이용하여 Dog 생성
AnimalFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.makeSound(); // 출력: Woof!
// Cat을 생성하는 팩터리를 이용하여 Cat 생성
AnimalFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.makeSound(); // 출력: Meow!
}
}
이렇게 클라이언트는 Dog와 Cat의 존재 유무를 몰라도 Factory에 의존하여 객체를 생성할 수 있다.
스프링에서는?
FactoryBean을 확장하여 스프링에서는 빈을 생성할 때, 팩토리 메서드 패턴을 사용한다.
import org.springframework.beans.factory.FactoryBean;
// 팩토리 역할을 하는 FactoryBean 인터페이스를 구현한 클래스
public class MyServiceFactoryBean implements FactoryBean<MyService> {
// 팩토리 메서드 역할을 하는 메서드
@Override
public MyService getObject() throws Exception {
// 객체 생성 로직이 여기에 들어갑니다.
return new MyServiceImpl();
}
// 팩토리 메서드가 생성하는 객체의 타입을 지정
@Override
public Class<?> getObjectType() {
return MyService.class;
}
// 팩토리 빈의 싱글톤 여부 지정
@Override
public boolean isSingleton() {
return true;
}
}
// 팩토리 메서드로 생성되는 객체의 인터페이스를 정의한 인터페이스
public interface MyService {
void doSomething();
}
// 실제 구현 클래스
public class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("MyServiceImpl is doing something");
}
}
'JAVA' 카테고리의 다른 글
디자인 패턴 - Strategy, Template Callback (0) | 2024.01.20 |
---|---|
디자인 패턴 - Proxy, Decolator (0) | 2024.01.19 |
디자인 패턴 - Adapter (0) | 2024.01.19 |
SOLID (0) | 2024.01.18 |
BigDecimal 생성, 비교시 유의사항 (0) | 2024.01.17 |