디자인 패턴은 소프트웨어 개발에서 자주 발생하는 문제를 해결하기 위한 재사용 가능한 솔루션입니다. 디자인 패턴은 개발자들 사이에서 소프트웨어 설계에 대한 공통 언어를 제공하고, 코드의 구조와 품질을 향상시키는 데 도움을 줍니다.
디자인 패턴은 크게 세 가지 범주로 분류됩니다:
- 생성 패턴(Creational Patterns)
- 구조 패턴(Structural Patterns)
- 행위 패턴(Behavioral Patterns)
1. 생성 패턴(Creational Patterns)
생성 패턴은 객체 생성 메커니즘을 다루며, 객체 생성 과정을 추상화하여 객체 생성의 복잡성을 줄이고 유연성을 높입니다.
싱글톤 패턴(Singleton Pattern)
싱글톤 패턴은 클래스의 인스턴스가 오직 하나만 생성되도록 보장하고, 해당 인스턴스에 대한 전역 접근점을 제공합니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
|
cs |
팩토리 메서드 패턴(Factory Method Pattern)
팩토리 메서드 패턴은 객체 생성 로직을 서브클래스에게 위임하여, 객체 생성 과정을 캡슐화하고 유연성을 제공합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
public interface Product {
void use();
}
public class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println(“Using ConcreteProductA”);
}
}
public class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println(“Using ConcreteProductB”);
}
}
public abstract class Creator {
public abstract Product createProduct();
public void someOperation() {
Product product = createProduct();
product.use();
}
}
public class ConcreteCreatorA extends Creator {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
public class ConcreteCreatorB extends Creator {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
|
cs |
2. 구조 패턴(Structural Patterns)
구조 패턴은 클래스와 객체의 구성을 다루며, 더 큰 구조를 형성하기 위해 클래스와 객체를 어떻게 조합할 수 있는지를 설명합니다.
어댑터 패턴(Adapter Pattern)
어댑터 패턴은 호환되지 않는 인터페이스를 가진 클래스들을 함께 작동시키기 위해 사용됩니다. 어댑터 클래스를 생성하여 원래 인터페이스를 다른 인터페이스로 변환합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public interface Target {
void request();
}
public class Adaptee {
public void specificRequest() {
System.out.println(“Specific Request”);
}
}
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
|
cs |
데코레이터 패턴(Decorator Pattern)
데코레이터 패턴은 객체에 동적으로 새로운 책임을 추가할 수 있게 해줍니다. 데코레이터 클래스를 사용하여 기존 객체를 감싸고 추가적인 기능을 제공합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public interface Component {
void operation();
}
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println(“ConcreteComponent Operation”);
}
}
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
additionalOperationA();
}
private void additionalOperationA() {
System.out.println(“Additional Operation A”);
}
}
|
cs |
3. 행위 패턴(Behavioral Patterns)
행위 패턴은 알고리즘과 객체 간의 책임 할당에 중점을 둡니다. 객체 간의 통신 패턴을 정의하고, 복잡한 제어 흐름을 단순화합니다.
옵저버 패턴(Observer Pattern)
옵저버 패턴은 객체 간의 일대다 의존 관계를 정의합니다. 한 객체의 상태가 변경되면 그에 의존하는 모든 객체에게 자동으로 알림이 전달됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
public interface Observer {
void update();
}
public class ConcreteObserverA implements Observer {
@Override
public void update() {
System.out.println(“ConcreteObserverA Updated”);
}
}
public class ConcreteObserverB implements Observer {
@Override
public void update() {
System.out.println(“ConcreteObserverB Updated”);
}
}
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
public void someBusinessLogic() {
// …
notifyObservers();
}
}
|
cs |
전략 패턴(Strategy Pattern)
전략 패턴은 알고리즘 패밀리를 정의하고 각 알고리즘을 캡슐화하여 상호 교환 가능하게 만듭니다. 클라이언트 코드에서 알고리즘을 독립적으로 변경할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public interface Strategy {
void execute();
}
public class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println(“Executing Strategy A”);
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println(“Executing Strategy B”);
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
|
cs |
디자인 패턴은 소프트웨어 개발에서 검증된 솔루션을 제공하며, 개발자들이 더 나은 설계를 하는 데 도움을 줍니다. 각 패턴의 사용 목적과 상황을 이해하고, 프로젝트의 요구사항에 맞게 적용하는 것이 중요합니다.