OOP와 DI

이규훈·2023년 4월 18일

OOP

OOP (객체 지향 프로그래밍, Object-Oriented Programming)은 프로그래밍 패러다임 중 하나로, 객체라는 개념을 사용하여 코드를 구성하는 방식입니다. 객체는 속성(attribute)과 메서드(method)를 가지며, 이를 통해 상태(state)와 행동(behavior)을 캡슐화합니다. 객체 지향 프로그래밍의 주요 원칙은 캡슐화(encapsulation), 상속(inheritance), 다형성(polymorphism) 및 추상화(abstraction)입니다. 이러한 원칙들을 통해 코드의 재사용성, 확장성, 유지보수성 등이 향상됩니다.

DI

DI (의존성 주입, Dependency Injection)은 소프트웨어 설계 패턴 중 하나로, 객체 간의 의존성을 관리하는 방법입니다. 의존성 주입을 사용하면 객체는 직접적으로 다른 객체를 생성하거나 참조하는 대신, 외부에서 생성된 객체를 주입받아 사용합니다. 이를 통해 결합도(coupling)가 낮아지고, 유연성 및 테스트 용이성이 향상됩니다. DI는 주로 인터페이스를 사용하여 구현되며, 다양한 형태로 사용될 수 있습니다 (예: 생성자 주입, 세터 주입, 인터페이스 주입 등)

OOP 예시

# 객체 지향 프로그래밍(OOP) 예시
class Animal:
    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        return "멍멍"

class Cat(Animal):
    def make_sound(self):
        return "야옹"

def print_animal_sound(animal):
    print(animal.make_sound())

dog = Dog()
cat = Cat()

print_animal_sound(dog)  # 출력: 멍멍
print_animal_sound(cat)  # 출력: 야옹

위의 예시에서 Animal 클래스는 추상화를 사용하여 공통 인터페이스를 제공하고, Dog와 Cat 클래스는 상속을 통해 Animal 클래스의 행동을 확장하고 구체화합니다.

DI 예시

# 의존성 주입(DI) 예시
class SoundMaker:
    def make_sound(self):
        pass

class DogSoundMaker(SoundMaker):
    def make_sound(self):
        return "멍멍"

class CatSoundMaker(SoundMaker):
    def make_sound(self):
        return "야옹"

class Animal:
    def __init__(self, sound_maker):
        self.sound_maker = sound_maker

    def make_sound(self):
        return self.sound_maker.make_sound()

def print_animal_sound(animal):
    print(animal.make_sound())

dog_sound_maker = DogSoundMaker()
cat_sound_maker = CatSoundMaker()

dog = Animal(dog_sound_maker)
cat = Animal(cat_sound_maker)

print_animal_sound(dog)  # 출력: 멍멍
print_animal_sound(cat)  # 출력: 야옹

이 코드는 파이썬을 사용하여 의존성 주입(Dependency Injection, DI) 패턴을 구현한 예시입니다. 아래는 코드에 대한 간단한 해설입니다.

SoundMaker 클래스는 make_sound 메서드를 가진 기본 클래스입니다. 이 클래스는 인터페이스 역할을 하며, 구체적인 구현은 서브클래스에서 제공됩니다.

DogSoundMaker와 CatSoundMaker 클래스는 SoundMaker 클래스를 상속받아 구체적인 구현을 제공합니다. 각각 개와 고양이의 소리를 반환하는 make_sound 메서드를 정의합니다.

Animal 클래스는 동물을 나타내며, init 메서드를 통해 sound_maker 객체를 주입받습니다. 이렇게 하면 Animal 클래스는 외부에서 전달된 sound_maker 객체를 사용하여 소리를 출력할 수 있습니다.

print_animal_sound 함수는 Animal 객체를 인자로 받아 해당 객체의 make_sound 메서드를 호출하고, 결과를 출력합니다.

dog_sound_maker와 cat_sound_maker 객체는 각각 DogSoundMaker와 CatSoundMaker 클래스의 인스턴스를 생성합니다.

dog와 cat 객체는 Animal 클래스의 인스턴스를 생성하며, 각각의 sound_maker 객체를 주입합니다.

print_animal_sound 함수를 사용하여 dog와 cat 객체의 소리를 출력합니다. 출력 결과는 "멍멍"과 "야옹"입니다.

이 예제에서 의존성 주입 패턴을 사용함으로써 Animal 클래스와 구체적인 소리 출력 방식에 대한 결합도를 낮출 수 있습니다. 이를 통해 코드의 유연성과 테스트 용이성이 향상됩니다.

위의 예시에서 SoundMaker 인터페이스와 구체적인 구현체인 DogSoundMaker와 CatSoundMaker 클래스가 있습니다. Animal 클래스는 SoundMaker 인터페이스를 구현한 객체를 의존성 주입을 통해 받아 사용합니다. 이를 통해 Animal 클래스와 소리를 만드는 방식에 대한 결합도를 낮추고 유연성을 높일 수 있습니다. DI는 객체가 직접적으로 다른 객체를 생성하거나 참조하는 대신, 외부에서 생성된 객체를 주입받아 사용하는 것을 의미합니다. 이를 통해 결합도(coupling)를 낮추고, 유연성 및 테스트 용이성이 향상됩니다.

자바 DI 예시

// 메시지 출력 인터페이스 정의
interface MessagePrinter {
    void printMessage();
}

// 인터페이스를 구현하는 클래스 정의
class ConsoleMessagePrinter implements MessagePrinter {
    @Override
    public void printMessage() {
        System.out.println("Hello, Console!");
    }
}

class ErrorMessagePrinter implements MessagePrinter {
    @Override
    public void printMessage() {
        System.err.println("Error: Something went wrong!");
    }
}

// DI를 사용하는 클래스 정의
class Application {
    private MessagePrinter messagePrinter;

    // 생성자를 통한 의존성 주입
    public Application(MessagePrinter messagePrinter) {
        this.messagePrinter = messagePrinter;
    }

    public void run() {
        messagePrinter.printMessage();
    }
}

// 메인 메소드
public class Main {
    public static void main(String[] args) {
        MessagePrinter consolePrinter = new ConsoleMessagePrinter();
        MessagePrinter errorPrinter = new ErrorMessagePrinter();

        // 의존성 주입을 통해 Application 객체 생성
        Application app1 = new Application(consolePrinter);
        Application app2 = new Application(errorPrinter);

        app1.run();  // 출력: Hello, Console!
        app2.run();  // 출력: Error: Something went wrong!
    }
}

이 코드는 자바를 사용하여 의존성 주입(Dependency Injection, DI) 패턴을 구현한 예시입니다. 아래는 코드에 대한 간단한 해설입니다.

MessagePrinter 인터페이스는 메시지 출력을 위한 메서드인 printMessage를 정의합니다. 이 인터페이스를 구현한 클래스들은 메시지를 출력하는 방법을 제공합니다.

ConsoleMessagePrinter 클래스는 MessagePrinter 인터페이스를 구현하며, 콘솔에 메시지를 출력하는 방법을 제공합니다.

ErrorMessagePrinter 클래스는 MessagePrinter 인터페이스를 구현하며, 에러 메시지를 출력하는 방법을 제공합니다.

Application 클래스는 메시지 출력 방식에 대한 의존성을 주입 받습니다. messagePrinter 필드를 가지고 있으며, 생성자를 통해 의존성을 주입받습니다.

run 메서드는 주입받은 messagePrinter 객체의 printMessage 메서드를 호출하여 메시지를 출력합니다.

Main 클래스의 main 메서드에서는 ConsoleMessagePrinter와 ErrorMessagePrinter 객체를 생성하고, 이를 Application 객체에 주입하여 사용합니다.

app1.run() 호출 시, consolePrinter 객체를 사용하여 메시지가 콘솔에 출력됩니다. 출력 결과는 "Hello, Console!"입니다.

app2.run() 호출 시, errorPrinter 객체를 사용하여 에러 메시지가 출력됩니다. 출력 결과는 "Error: Something went wrong!"입니다.

이 예제에서 의존성 주입 패턴을 사용함으로써 Application 클래스와 구체적인 메시지 출력 방식에 대한 결합도를 낮출 수 있습니다. 이를 통해 코드의 유연성과 테스트 용이성이 향상됩니다.

위의 예시에서 MessagePrinter 인터페이스는 메시지 출력을 위한 메서드를 정의하고, ConsoleMessagePrinter와 ErrorMessagePrinter 클래스는 이 인터페이스를 구현합니다. Application 클래스는 MessagePrinter 인터페이스를 구현한 객체를 생성자를 통해 주입받아 사용합니다. 이를 통해 Application 클래스와 메시지 출력 방식에 대한 결합도를 낮추고 유연성을 높일 수 있습니다.

profile
개발취준생

0개의 댓글