일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- Maui
- 오류
- MVVM
- typescript
- React JS
- MSSQL
- Flutter
- 파이어베이스
- Animation
- HTML
- 바인딩
- .NET
- 함수
- spring boot
- 닷넷
- 애니메이션
- db
- 마우이
- MS-SQL
- GitHub
- JavaScript
- 깃허브
- Binding
- 자바스크립트
- page
- AnimationController
- Firebase
- 플러터
- listview
- 리엑트
Archives
- Today
- Total
개발노트
4. [ASP .NET Core] 의존성 역전 원칙 (DIP) 본문
반응형
DIP (Dependency Inversion Principle)란?
DIP(의존성 역전 원칙)는 SOLID 원칙 중 하나로, 상위 모듈이 하위 모듈에 의존하지 않도록 설계하는 것을 말합니다.
즉, 구체적인 클래스 대신 추상화(인터페이스나 추상 클래스)에 의존해야 합니다.
DIP 적용 전
public class Dog
{
public void Eat()
{
Console.WriteLine("The dog is eating.");
}
}
public class Cat
{
public void Eat()
{
Console.WriteLine("The cat is eating.");
}
}
// AnimalFeeder 클래스가 Dog와 Cat에 의존
public class AnimalFeeder
{
private Dog dog;
private Cat cat;
public AnimalFeeder()
{
dog = new Dog();
cat = new Cat();
}
public void FeedDog()
{
dog.Eat();
}
public void FeedCat()
{
cat.Eat();
}
}
DIP 적용 후
IAnimal.cs (인터페이스 Eat, 추상화)
// 동물의 공통 행동을 정의하는 인터페이스
public interface IAnimal
{
void Eat();
}
Dog, Cat (IAnimal 상속 받음, Eat 구현, 하위 클래스)
// Dog 클래스
public class Dog : IAnimal
{
public void Eat()
{
Console.WriteLine("The dog is eating.");
}
}
// Cat 클래스
public class Cat : IAnimal
{
public void Eat()
{
Console.WriteLine("The cat is eating.");
}
}
AnimalFeeder.cs (인터페이스인 IAnimal에만 의존, 모듈)
// AnimalFeeder 클래스는 인터페이스(IAnimal)에만 의존
public class AnimalFeeder
{
private readonly IAnimal _animal;
public AnimalFeeder(IAnimal animal)
{
_animal = animal;
}
public void Feed()
{
_animal.Eat();
}
}
Program.cs (사용)
class Program
{
static void Main(string[] args)
{
// Dog 객체를 주입하여 동작
IAnimal dog = new Dog();
var feeder = new AnimalFeeder(dog);
feeder.Feed(); // 출력: The dog is eating.
// Cat 객체를 주입하여 동작
IAnimal cat = new Cat();
feeder = new AnimalFeeder(cat);
feeder.Feed(); // 출력: The cat is eating.
}
}
DIP의 주요 개념 요약
- 상위 모듈(AnimalFeeder)은 하위 모듈(Dog, Cat)에 의존하지 않는다.
- 상위와 하위 모듈 모두 추상화(IAnimal)에 의존한다.
- 구체적인 구현체(Dog, Cat)는 추상화(IAnimal)를 구현한다.
DIP가 필요한 이유
- 확장성: 새로운 동물 클래스(Bird, Fish 등)를 추가하더라도 AnimalFeeder를 수정할 필요가 없습니다.
- 테스트 가능성: 인터페이스를 통해 목(Mock) 객체를 쉽게 주입할 수 있습니다.
- 유연성: 클래스 간 결합도를 낮추고, 시스템을 재사용 가능하게 만듭니다.
[High-Level Module]
AnimalFeeder
|
▼
[Abstraction]
IAnimal
/ \
▼ ▼
[Low-Level] [Low-Level]
Dog Cat
DIP와 DI 같이 사용
1. DIP로 상위(AnimalFeeder), 하위(cat,dog) 클래스가 추상화 클래스(IAnimal)에 의존하게 됨
2. DI로 제어 의존권은 컨테이너(container)에게 줌
즉, AnimalFeeder에 IAnimal 주입을 컨테이너가 알아서 해줌(AnimalFeeder에서 IAnimal를 직접 생성 등록안함)
using SimpleInjector;
class Program
{
static void Main(string[] args)
{
// DI 컨테이너 생성
var container = new Container();
// IAnimal에 대한 구현체(Dog) 등록
container.Register<IAnimal, Dog>();
// AnimalFeeder에 IAnimal 구현체 주입
container.Register<AnimalFeeder>();
// AnimalFeeder 인스턴스 가져오기
var feeder = container.GetInstance<AnimalFeeder>();
feeder.Feed(); // 출력: The dog is eating.
}
}
추가 예제
using System;
using System.Collections.Generic;
// 게임 아이템 인터페이스
public interface IGameItem
{
string Name { get; }
decimal Price { get; }
void DisplayInfo();
}
// 재료 아이템 클래스
public class MaterialItem : IGameItem
{
public string Name { get; }
public decimal Price { get; }
public MaterialItem(string name, decimal price)
{
Name = name;
Price = price;
}
public void DisplayInfo()
{
Console.WriteLine($"[재료] {Name}, 가격: {Price}골드");
}
}
// 장비 아이템 클래스
public class EquipmentItem : IGameItem
{
public string Name { get; }
public decimal Price { get; }
public EquipmentItem(string name, decimal price)
{
Name = name;
Price = price;
}
public void DisplayInfo()
{
Console.WriteLine($"[장비] {Name}, 가격: {Price}골드");
}
}
// 주문 클래스
public class Order
{
private readonly IList<IGameItem> _gameItems;
public Order()
{
_gameItems = new List<IGameItem>();
}
// 아이템 추가
public void AddGameItem(IGameItem gameItem)
{
_gameItems.Add(gameItem);
Console.WriteLine($"아이템 '{gameItem.Name}'이(가) 추가되었습니다.");
}
// 아이템 제거
public void RemoveGameItem(IGameItem gameItem)
{
if (_gameItems.Contains(gameItem))
{
_gameItems.Remove(gameItem);
Console.WriteLine($"아이템 '{gameItem.Name}'이(가) 제거되었습니다.");
}
else
{
Console.WriteLine($"'{gameItem.Name}'은(는) 주문 목록에 없습니다.");
}
}
// 주문 처리
public void ProcessOrder()
{
Console.WriteLine("주문 처리 중...");
foreach (var gameItem in _gameItems)
{
gameItem.DisplayInfo();
}
Console.WriteLine($"총 아이템 수: {_gameItems.Count}");
}
}
Program.cs
class Program
{
static void Main(string[] args)
{
// 게임 아이템 생성
IGameItem item1 = new MaterialItem("철광석", 15);
IGameItem item2 = new EquipmentItem("장검", 120);
IGameItem item3 = new MaterialItem("목재", 5);
IGameItem item4 = new EquipmentItem("방패", 80);
// 주문 생성
var order = new Order();
// 아이템 추가
order.AddGameItem(item1);
order.AddGameItem(item2);
// 주문 처리 (현재 2개 아이템)
order.ProcessOrder();
Console.WriteLine();
// 아이템 제거 및 추가
order.RemoveGameItem(item1);
order.AddGameItem(item3);
order.AddGameItem(item4);
// 주문 처리 (현재 3개 아이템)
order.ProcessOrder();
}
}
[콘솔 출력]
아이템 '철광석'이(가) 추가되었습니다.
아이템 '장검'이(가) 추가되었습니다.
주문 처리 중...
[재료] 철광석, 가격: 15골드
[장비] 장검, 가격: 120골드
총 아이템 수: 2
아이템 '철광석'이(가) 제거되었습니다.
아이템 '목재'이(가) 추가되었습니다.
아이템 '방패'이(가) 추가되었습니다.
주문 처리 중...
[장비] 장검, 가격: 120골드
[재료] 목재, 가격: 5골드
[장비] 방패, 가격: 80골드
총 아이템 수: 3
구조적 확장 가능성
- 새로운 아이템 유형 추가
- PotionItem(예: 체력 물약), QuestItem(예: 특정 퀘스트에 필요한 아이템) 등으로 확장 가능.
- 아이템 분류 필터링
- 주문 내 특정 유형의 아이템만 처리하도록 추가 기능 구현 가능.
- 아이템 속성 추가
- EquipmentItem에 내구도나 공격력 속성 추가, MaterialItem에 등급 속성 추가.
- DIP 유지
- 인터페이스를 통해 새로운 아이템을 추가하더라도 Order 클래스는 기존 코드를 변경하지 않음.
이런 구조를 통해 DIP를 준수하며 유연한 설계를 유지할 수 있습니다.
반응형
'서버 개발 > ASP .NET Core' 카테고리의 다른 글
5. [ASP .NET Core] IList 사용하기 (0) | 2024.11.17 |
---|---|
3. [ASP .NET Core] 의존성 주입(DI), IoC 란 무엇인가? (with Simple Injector) (0) | 2024.11.17 |
2. [ASP .NET Core] 간단 API 만들기(with Dapper) (0) | 2024.11.10 |
1. [ASP .NET Core] 프로젝트 환경 세팅하기 (0) | 2024.11.10 |
Comments