의존성 주입(Dependency Injection, DI)은 객체 지향 프로그래밍에서 객체 간의 의존성을 관리하는 디자인 패턴입니다. DI는 객체가 필요한 의존성을 직접 생성하거나 관리하는 대신, 외부에서 의존성을 주입받도록 하는 방식입니다. 이를 통해 코드의 결합도를 낮추고, 테스트 용이성과 유연성을 높일 수 있습니다.
의존성 주입의 장점
- 결합도 감소: 객체가 직접 의존성을 생성하지 않으므로, 객체 간의 결합도가 줄어듭니다.
- 테스트 용이성: 의존성을 주입함으로써 모의 객체(mock objects)를 사용하여 테스트가 용이해집니다.
- 유연성 향상: 의존성을 런타임에 주입할 수 있어, 구현을 쉽게 변경하거나 교체할 수 있습니다.
의존성 주입의 방식
- 생성자 주입(Constructor Injection): 의존성을 객체의 생성자에서 주입합니다.
- 세터 주입(Setter Injection): 의존성을 객체의 세터 메서드를 통해 주입합니다.
- 인터페이스 주입(Interface Injection): 의존성을 객체가 구현한 인터페이스를 통해 주입합니다.
예제: 병합 정렬과 의존성 주입
병합 정렬 구현을 예로 들어, 의존성 주입을 적용해 보겠습니다. 여기서는 병합 정렬 알고리즘을 사용하는 클래스를 만들고, 병합 정렬 구현을 의존성으로 주입받는 방식을 사용합니다.
1. 병합 정렬 구현 (merge_sort.py)
병합 정렬 알고리즘을 별도의 모듈로 유지합니다.
python
코드 복사
def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left_half = merge_sort(arr[:mid]) right_half = merge_sort(arr[mid:]) return merge(left_half, right_half) def merge(left, right): sorted_array = [] left_index, right_index = 0, 0 while left_index < len(left) and right_index < len(right): if left[left_index] < right[right_index]: sorted_array.append(left[left_index]) left_index += 1 else: sorted_array.append(right[right_index]) right_index += 1 sorted_array.extend(left[left_index:]) sorted_array.extend(right[right_index:]) return sorted_array
2. 병합 정렬을 사용하는 클래스 (sorter.py)
병합 정렬 기능을 사용하는 클래스를 작성하고, 생성자 주입을 통해 병합 정렬 함수를 주입받습니다.
python
코드 복사
class Sorter: def __init__(self, sort_function): self.sort_function = sort_function def sort(self, arr): return self.sort_function(arr)
3. 메인 실행 코드 (main.py)
병합 정렬 알고리즘을 주입하여 Sorter 클래스를 사용합니다.
python
코드 복사
from merge_sort import merge_sort from sorter import Sorter def main(): sorter = Sorter(sort_function=merge_sort) # 사용자로부터 입력을 받습니다. user_input = input("정렬할 숫자들을 공백으로 구분하여 입력하세요: ") unsorted_array = list(map(int, user_input.split())) # 병합 정렬을 수행합니다. sorted_array = sorter.sort(unsorted_array) # 정렬된 배열을 출력합니다. print("정렬된 배열:", sorted_array) if __name__ == "__main__": main()
4. 테스트 코드 (test_sorter.py)
Sorter 클래스를 테스트하며, 병합 정렬 함수는 모의 객체로 교체하여 테스트할 수 있습니다.
python
코드 복사
import unittest from sorter import Sorter class TestSorter(unittest.TestCase): def test_sort(self): def mock_sort(arr): return sorted(arr) # 단순히 기본 정렬을 모의로 사용 sorter = Sorter(sort_function=mock_sort) test_cases = [ { "input": [38, 27, 43, 3, 9, 82, 10], "expected": [3, 9, 10, 27, 38, 43, 82] }, { "input": [5, 2, 9, 1, 5, 6], "expected": [1, 2, 5, 5, 6, 9] }, { "input": [0], "expected": [0] }, { "input": [], "expected": [] } ] for case in test_cases: input_data = case["input"] expected_output = case["expected"] result = sorter.sort(input_data) self.assertEqual(result, expected_output, f"Failed for input: {input_data}") if __name__ == "__main__": unittest.main()
요약
- 프로덕션 코드 (merge_sort.py):
- 병합 정렬 알고리즘의 구현을 포함합니다.
- 서비스 클래스 (sorter.py):
- Sorter 클래스를 통해 병합 정렬 알고리즘을 주입받아 사용합니다. 의존성을 생성자 주입 방식으로 관리합니다.
- 메인 코드 (main.py):
- Sorter 클래스를 사용하여 실제 정렬 작업을 수행합니다. 병합 정렬 구현을 주입합니다.
- 테스트 코드 (test_sorter.py):
- Sorter 클래스를 테스트하며, 병합 정렬 함수 대신 모의 객체를 사용하여 테스트합니다.
이러한 방식으로 의존성 주입을 적용하면 코드의 결합도를 낮추고, 테스트와 유지 보수가 용이해집니다.