본문 바로가기

Learning/.programming

[디자인 패턴] 4) 추가 패턴

728x90

4. 추가 패턴 (Additional Patterns)

추가 패턴은 생성, 구조, 행위 패턴에 포함되지 않는 특수한 목적의 디자인 패턴이다.
이 패턴들은 특정 상황에서 문제를 해결하거나, 성능을 최적화하는 데 유용하게 사용된다.


---

4.1 Null Object Pattern (널 객체 패턴)

개념:
객체가 null인 경우, null 체크를 하지 않고도 정상적인 동작을 수행할 수 있도록 기본 객체를 제공하는 패턴.

구조 다이어그램:

+------------+
        |   Object   |
        +------------+
              |
    +---------+--------+
    |                  |
+-------+          +---------+
| Real  |          |   Null  |
|Object |          |  Object |
+-------+          +---------+

예제 코드:

interface Animal {
    void makeSound();
}

class Dog implements Animal {
    public void makeSound() {
        System.out.println("Bark");
    }
}

class NullAnimal implements Animal {
    public void makeSound() {
        System.out.println("No animal found.");
    }
}

class AnimalFactory {
    public static Animal getAnimal(String type) {
        if ("Dog".equalsIgnoreCase(type)) {
            return new Dog();
        }
        return new NullAnimal();
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = AnimalFactory.getAnimal("Dog");
        Animal unknown = AnimalFactory.getAnimal("Cat");

        dog.makeSound();
        unknown.makeSound();
    }
}

출력:

Bark  
No animal found.

장단점:

장점: null 체크를 줄여 코드 가독성 향상

단점: 모든 경우에 null 객체를 정의해야 하므로 코드가 늘어날 수 있음



---

4.2 Dependency Injection Pattern (의존성 주입 패턴)

개념:
객체가 필요로 하는 의존성을 외부에서 주입받는 방식으로 객체 간의 결합을 줄이는 패턴.

구조 다이어그램:

+-----------+
        |   Client  |
        +-----------+
              |
        +-----------+
        |  Service  |
        +-----------+

예제 코드:

interface Service {
    void execute();
}

class EmailService implements Service {
    public void execute() {
        System.out.println("Sending email...");
    }
}

class Notification {
    private Service service;

    public Notification(Service service) {
        this.service = service;
    }

    public void notifyUser() {
        service.execute();
    }
}

public class Main {
    public static void main(String[] args) {
        Service emailService = new EmailService();
        Notification notification = new Notification(emailService);
        notification.notifyUser();
    }
}

출력:

Sending email...

장단점:

장점: 객체 간의 결합을 줄여서 테스트 용이성 향상

단점: 코드가 분리되면서 초기화 과정이 복잡해질 수 있음



---

4.3 Lazy Initialization Pattern (지연 초기화 패턴)

개념:
객체의 초기화 비용이 클 경우, 실제로 필요할 때까지 객체 생성을 지연시키는 패턴.

구조 다이어그램:

+-----------+
        | Singleton |
        +-----------+
              |
        +-----------+
        | Instance  |
        +-----------+

예제 코드:

class HeavyObject {
    public HeavyObject() {
        System.out.println("Heavy object created.");
    }
}

class LazyInitializer {
    private HeavyObject heavyObject;

    public HeavyObject getInstance() {
        if (heavyObject == null) {
            heavyObject = new HeavyObject();
        }
        return heavyObject;
    }
}

public class Main {
    public static void main(String[] args) {
        LazyInitializer initializer = new LazyInitializer();
        System.out.println("Object not created yet.");

        initializer.getInstance();
        initializer.getInstance();
    }
}

출력:

Object not created yet.  
Heavy object created.

장단점:

장점: 메모리 절약, 불필요한 객체 생성을 방지

단점: 멀티스레딩 환경에서 동기화 처리가 필요할 수 있음



---

4.4 Extension Object Pattern (확장 객체 패턴)

개념:
객체에 새로운 기능을 추가할 때, 기존 클래스를 수정하지 않고 확장 객체를 통해 기능을 추가하는 패턴.

구조 다이어그램:

+----------+
        |  Client  |
        +----------+
              |
        +----------+
        |  Object  |
        +----------+
              |
        +----------+
        | Extension |
        +----------+

예제 코드:

interface Extension {
    void extend();
}

class BasicObject {
    void operation() {
        System.out.println("Basic Operation");
    }
}

class ExtensionA implements Extension {
    public void extend() {
        System.out.println("Extension A");
    }
}

class ExtensionB implements Extension {
    public void extend() {
        System.out.println("Extension B");
    }
}

public class Main {
    public static void main(String[] args) {
        BasicObject object = new BasicObject();
        object.operation();

        Extension extA = new ExtensionA();
        extA.extend();

        Extension extB = new ExtensionB();
        extB.extend();
    }
}

출력:

Basic Operation  
Extension A  
Extension B

장단점:

장점: 기존 클래스의 코드를 변경하지 않고 확장 가능

단점: 확장 객체가 많아질 경우 관리가 어려워질 수 있음



---

4.5 Double-Checked Locking Pattern (이중 검사 잠금 패턴)

개념:
멀티스레드 환경에서 객체의 인스턴스를 한 번만 생성하도록 보장하는 패턴.
첫 번째 검사에서 인스턴스가 null인지 확인하고, 두 번째 검사에서 동기화 블록 내에서 객체를 생성한다.

구조 다이어그램:

+-----------+
        | Singleton |
        +-----------+
              |
        +-----------+
        | Instance  |
        +-----------+

예제 코드:

class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

public class Main {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2);
    }
}

출력:

true

장단점:

장점: 객체 생성 비용 절감, 멀티스레드 안전성 보장

단점: 코드가 복잡해질 수 있으며, Java 1.4 이전 버전에서는 문제가 발생할 수 있음




300x250