JAVA/JAVA Design Pattern

프로젝트에서의 디자인 패턴 적용 사례 및 주의점

임베디드 친구 2025. 1. 7. 08:45
반응형

디자인 패턴은 소프트웨어 설계에서 자주 등장하는 문제에 대한 재사용 가능한 솔루션입니다. 실제 프로젝트에서 디자인 패턴을 어떻게 사용하고 문제를 해결했는지 사례를 통해 설명하고, 패턴 남용을 방지하는 방법도 살펴보겠습니다.


1. 실제 프로젝트에서 디자인 패턴 사용 사례

1.1 Singleton 패턴 - 데이터베이스 연결 관리

프로젝트에서 데이터베이스 연결 객체를 하나만 생성하여 사용해야 하는 경우, Singleton 패턴을 사용할 수 있습니다. 이 패턴을 통해 객체 생성 비용을 절감하고 데이터베이스 접근을 일관성 있게 유지할 수 있습니다.

예제 코드

public class DatabaseConnection {
    private static DatabaseConnection instance;
    private Connection connection;

    private DatabaseConnection() {
        try {
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static synchronized DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }

    public Connection getConnection() {
        return connection;
    }
}

사용 예

public class Main {
    public static void main(String[] args) {
        DatabaseConnection dbConnection = DatabaseConnection.getInstance();
        Connection conn = dbConnection.getConnection();
        System.out.println("데이터베이스 연결 성공!");
    }
}
  • 장점: 객체 생성을 제한하여 리소스를 절약합니다.
  • 단점: 멀티스레드 환경에서 주의가 필요합니다. synchronized를 적절히 사용해야 합니다.

1.2 Factory 패턴 - 객체 생성 로직 캡슐화

Factory 패턴은 객체 생성을 캡슐화하여 코드의 유연성과 확장성을 높여줍니다. 예를 들어, 여러 종류의 Shape 객체를 생성하는 상황에서 유용합니다.

예제 코드

interface Shape {
    void draw();
}

class Circle implements Shape {
    public void draw() {
        System.out.println("원 그리기");
    }
}

class Rectangle implements Shape {
    public void draw() {
        System.out.println("사각형 그리기");
    }
}

class ShapeFactory {
    public static Shape getShape(String shapeType) {
        if (shapeType == null) return null;
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        }
        return null;
    }
}

public class FactoryPatternDemo {
    public static void main(String[] args) {
        Shape shape1 = ShapeFactory.getShape("CIRCLE");
        shape1.draw();

        Shape shape2 = ShapeFactory.getShape("RECTANGLE");
        shape2.draw();
    }
}

출력 결과

원 그리기
사각형 그리기
  • 장점: 객체 생성 코드를 변경하지 않고 새로운 객체를 추가할 수 있습니다.
  • 단점: 비즈니스 로직과 분리되어 객체 관리가 복잡해질 수 있습니다.

2. 여러 패턴을 조합하여 문제 해결하기

실제 프로젝트에서는 단일 패턴만 사용하지 않고 여러 패턴을 조합해서 문제를 해결하는 경우가 많습니다.

사례: Observer + Singleton 패턴

상황: 채팅 애플리케이션에서 메시지가 수신될 때 UI에 알림을 보내는 경우.

  • Singleton: 메시지 관리 객체를 단 하나만 생성.
  • Observer: UI 컴포넌트를 구독자로 등록하고 메시지를 수신하면 알림.

예제 코드

import java.util.ArrayList;
import java.util.List;

// Observer 인터페이스
interface Observer {
    void update(String message);
}

// Subject (Observable)
class MessageManager {
    private static MessageManager instance;
    private List<Observer> observers = new ArrayList<>();

    private MessageManager() {}

    public static MessageManager getInstance() {
        if (instance == null) {
            instance = new MessageManager();
        }
        return instance;
    }

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

// Observer 구현체
class ChatUI implements Observer {
    private String name;

    public ChatUI(String name) {
        this.name = name;
    }

    public void update(String message) {
        System.out.println(name + " UI 알림: " + message);
    }
}

public class ChatAppDemo {
    public static void main(String[] args) {
        MessageManager messageManager = MessageManager.getInstance();

        ChatUI ui1 = new ChatUI("User1");
        ChatUI ui2 = new ChatUI("User2");

        messageManager.addObserver(ui1);
        messageManager.addObserver(ui2);

        messageManager.notifyObservers("새 메시지가 도착했습니다!");
    }
}

출력 결과

User1 UI 알림: 새 메시지가 도착했습니다!
User2 UI 알림: 새 메시지가 도착했습니다!

3. 디자인 패턴을 사용할 때의 주의점 및 남용 방지

디자인 패턴은 강력한 도구이지만 잘못 사용하거나 남용하면 코드가 오히려 복잡해질 수 있습니다.

주의점

  1. 불필요한 패턴 적용을 피하라: 단순한 문제에 복잡한 패턴을 적용하면 유지 보수가 어려워집니다.
  2. 과도한 추상화: 추상화가 과도하면 가독성이 떨어집니다.
  3. 프로젝트 요구사항에 맞는 패턴 선택: 요구사항과 맞지 않는 패턴을 억지로 적용하지 마세요.

남용 방지

  • KISS 원칙: "Keep It Simple, Stupid"를 항상 염두에 두고 설계합니다.
  • YAGNI 원칙: "You Aren't Gonna Need It" - 지금 당장 필요하지 않은 기능은 추가하지 않습니다.
  • 리팩토링: 디자인 패턴이 필요하다고 판단되면 그때 리팩토링을 통해 적용합니다.

4. 마무리

디자인 패턴은 코드의 재사용성과 유지 보수성을 높여주는 강력한 도구입니다. 하지만 남용하면 복잡도를 증가시킬 수 있으므로 프로젝트의 상황에 맞게 적절히 적용하는 것이 중요합니다.

오늘 예시로 든 Singleton, Factory, Observer 패턴은 실제 프로젝트에서 자주 사용되는 패턴입니다. 필요에 따라 패턴을 조합해서 더 큰 문제를 해결해 나가시기 바랍니다!

반응형