디자인 패턴은 개발하면서 반복적으로 발생하는 문제들에 대한 해결책을 제시한다.
선배 개발자도 현재 우리가 만난 문제와 똑같거나 비슷한 문제를 겪고, 해결하는 과정에서 이를 패턴으로 만들어간 것이다.
디자인 패턴은 용도에 따라 분류할 수 있다: 생성, 행동, 구조
객체 인스턴스를 생성하는 패턴.
(ex) Singleton, Factory, Prototype, Builder etc.
특정 클래스에 객체 인스턴스가 하나만 만들어지도록 하는 패턴
전역 변수 쓰듯이 이 객체 인스턴스를 어디서든지 접근할 수 있도록 메서드를 제공한다
생성자의 접근자를 private
로 제한하고, 클래스 내에서 private static
한 객체를 하나 생성한 다음, 외부에서 이 객체에 접근할 수 있는 getter
메서드를 제공한다.
public class HouseDaoImpl {
private static HouseDaoImpl impl = new HouseDaoImpl();
private HouseDaoImpl() {}
public static HouseDaoImpl getImpl() { return impl; }
...
}
용도
장점
단점
구상(implementation) 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공한다.
추상 팩토리 패턴의 요소
Char
인터페이스는 VictorianChair
, ModernChair
구상클래스에 의해 구현된다VictorianFactory
는 VictorianChair
, VictorianTable
등만 생성한다용도
장점
단점
빌더 패턴의 구성 요소
용도
점층적 생성자란 다음과 같다
class Pizza { Pizza(int size) { ... } Pizza(int size, boolean cheese) { ... } Pizza(int size, boolean cheese, boolean pepperoni) { ... } ...
Spring의 @Builder
@Builder
어노테이션을 선언하면 Lombok
이 해당 클래스에 대한 빌더 클래스를 자동으로 생성한다import lombok.Builder;
@Builder
public class User {
private String name;
private int age;
}
...
User user = User.builder()
.name("Alice")
.age(30)
.build();
클래스와 객체들이 상호작용하는 방법과 역할을 분담하는 방법을 다루는 패턴.
(ex) Template method, Singleton, Observer, State, Visitor, etc.
하나의 객체에 발생하는 모든 이벤트에 대하여 여러 객체에 이를 알리는 구독 메커니즘을 정의한다
옵저버 패턴의 구성 요소
public
메서드를 갖는다용도
장점
단점
구조를 유연하고 효율적으로 유지하면서, 더 큰 구조로 조립하는 방법을 다루는 패턴.
(ex) Adapter, Proxy, Decorator, Composite, etc.
객체의 구조를 건들 필요 없이 객체에 새 행위를 추가한다.
장점
// Base component
public interface Coffee {
String getDescription();
double cost();
}
// Concrete component
public class BasicCoffee implements Coffee {
public String getDescription() {
return "Basic Coffee";
}
public double cost() {
return 2.0;
}
}
// Decorator
public abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
public String getDescription() {
return decoratedCoffee.getDescription();
}
public double cost() {
return decoratedCoffee.cost();
}
}
// Concrete decorators
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return decoratedCoffee.getDescription() + ", Milk";
}
public double cost() {
return decoratedCoffee.cost() + 0.5;
}
}
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return decoratedCoffee.getDescription() + ", Sugar";
}
public double cost() {
return decoratedCoffee.cost() + 0.2;
}
}
// Usage
public class CoffeeShop {
public static void main(String[] args) {
Coffee coffee = new BasicCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
System.out.println(coffee.getDescription());
System.out.println("Total Cost: " + coffee.cost());
}
}
참고