...

์์กด ์ญ์ ์์น - DIP (Dependency Inversion Principle)
DIP ์์น์ด๋ ๊ฐ์ฒด์์ ์ด๋ค Class๋ฅผ ์ฐธ์กฐํด์ ์ฌ์ฉํด์ผํ๋ ์ํฉ์ด ์๊ธด๋ค๋ฉด, ๊ทธ Class๋ฅผ ์ง์ ์ฐธ์กฐํ๋ ๊ฒ์ด ์๋๋ผ ๊ทธ ๋์์ ์์ ์์(์ถ์ ํด๋์ค or ์ธํฐํ์ด์ค)๋ก ์ฐธ์กฐํ๋ผ๋ ์์น์ด๋ค.
๊ฐ์ฒด๋ค์ด ์๋ก ์ ๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ์ ๋๋ ์์กด ๊ด๊ณ๊ฐ ํ์ฑ๋๋๋ฐ, ์ด ๋ ๊ฐ์ฒด๋ค์ ๋๋ฆ๋๋ก์ ์์น์ ๊ฐ๊ณ ์ ๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ์์ผ ํ๋ ์ฝ์์ด ์๋ค. ์ฌ๊ธฐ์ ๋๋ฆ๋๋ก์ ์์น์ด๋ ์ถ์์ฑ์ด ๋ฎ์ ํด๋์ค๋ณด๋ค ์ถ์์ฑ์ด ๋์ ํด๋์ค์ ํต์ ์ ํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋๋ฐ ์ด๊ฒ์ด DIP ์์น์ด๋ค.
ํด๋์ค ๊ฐ ์์กด ๊ด๊ณ๋, ํ ํด๋์ค๊ฐ ์ด๋ค ๊ธฐ๋ฅ์ ์ํํ๋ ค๊ณ ํ ๋, ๋ค๋ฅธ ํด๋์ค์ ์๋น์ค๊ฐ ํ์ํ ๊ฒฝ์ฐ๋ฅผ ๋งํ๋ค.
๋ํ์ ์ผ๋ก A ํด๋์ค์ ๋ฉ์๋์์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ค๋ฅธ B ํด๋์ค์ ํ์ ์ผ๋ก ๋ฐ์ B ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๋, A ํด๋์ค๋ B ํด๋์ค์ ์์กดํ๋ค๊ณ ๋ณด๋ฉด ๋๋ค.
๋ค์ ๋งํ๋ฉด ํด๋ผ์ด์ธํธ(์ฌ์ฉ์)๊ฐ ์์ ๊ด๊ณ๋ก ์ด๋ฃจ์ด์ง ๋ชจ๋์ ๊ฐ์ ธ๋ค ์ฌ์ฉํ ๋, ํ์ ๋ชจ๋์ ์ง์ ์ธ์คํด์ค๋ฅผ ๊ฐ์ ธ๋ค ์ฐ์ง ๋ง๋ผ๋ ๋ป์ด๋ค. ์๋ํ๋ฉด ๊ทธ๋ ๊ฒ ํ ๊ฒฝ์ฐ, ํ์ ๋ชจ๋์ ๊ตฌ์ฒด์ ์ธ ๋ด์ฉ์ ํด๋ผ์ด์ธํธ๊ฐ ์์กดํ๊ฒ ๋์ด ํ์ ๋ชจ๋์ ๋ณํ๊ฐ ์์ ๋๋ง๋ค ํด๋ผ์ด์ธํธ๋ ์์ ๋ชจ๋์ ์ฝ๋๋ฅผ ์์ฃผ ์์ ํด์ผ ๋๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์ ํ๋ง๋๋ก ์์์ ์ธํฐํ์ด์ค ํ์ ์ ๊ฐ์ฒด๋ก ํต์ ํ๋ผ๋ ์์น์ด๋ค.

// ์ธํฐํ์ด์ค
interface Toy {}
class Robot implements Toy {}
class Lego implements Toy {}
class Doll implements Toy {}
// ํด๋ผ์ด์ธํธ
class Kid {
Toy toy; // ํฉ์ฑ
void setToY(Toy toy) {
this.toy = toy;
}
void play() {}
}
// ๋ฉ์ธ ๋ฉ์๋
public class Main {
public static void main(String[] args) {
Kid boy = Kid();
// 1. ์์ด๊ฐ ๋ก๋ด์ ๊ฐ์ง๊ณ ๋ ๋
Toy toy = new Robot();
boy.setToy(toy);
boy.play();
// ...
// 2. ์์ด๊ฐ ๋ ๊ณ ๋ฅผ ๊ฐ์ง๊ณ ๋ ๋
Toy toy = new Lego();
boy.setToy(toy);
boy.play();
}
}
์ค์ ์๋ฐ์์ ์ธํฐํ์ด์ค์ ๋ํด ํ์ตํ ๋ ๋งค๊ฐ๋ณ์๋ก ๊ฐ์ฒด๋ฅผ ๋ฐ์๋ ๊ตฌ์ฒด ํด๋์ค ํ์ ์ผ๋ก ๋ฐ๋๊ฒ ์๋๋ผ, ๋คํ์ฑ์ ์ด์ฉํด ์ธํฐํ์ด์ค ํ์ ์ผ๋ก ํต์ ํ๋ ๊ฒ์ด ์ข๋ค๊ณ ๋ฐฐ์ ์ ๊ฒ์ด๋ค.
๋ํ์ ์ผ๋ก ์ปฌ๋ ์ ํ๋ ์์ํฌ๋ฅผ ๋ค์ ์๋๋ฐ, ๋ณดํต ArrayList ๋ HashSet ์๋ฃํ์ ์ธ์คํด์คํ ํ ๋ ๋ณ์ ํ์ ์ ArrayList, HashSet ๊ฐ์ ๊ตฌ์ฒด ํด๋์ค ํ์ ์ผ๋ก ์ ์ธํ๋ ๊ฒ์ด ์๋, List ๋ Set ๊ฐ์ ์ธํฐํ์ด์ค ํ์ ์ผ๋ก ์ ์ธํ๋ ๊ฒ์ ๋ด์์ ๊ฒ์ด๋ค.
์ด๊ฒ๋ DIP ์์น์ ๋ฐ๋ฅธ ์ฝ๋ ์ ์ธ์ด๋ผ๊ณ ๋ด๋ ๋ฌด๋ฐฉํ๋ค.
// ๋ณ์ ํ์
์ ๊ณ ์์ค์ ๋ชจ๋์ธ ์ธํฐํ์ด์ค ํ์
์ผ๋ก ์ ์ธํ์ฌ ์ ์์ค์ ๋ชจ๋์ ํ ๋น
List<String> myList = new ArrayList()<>;
Set<String> mySet = new HashSet()<>;
Map<int, String> myMap = new HashMap()<>;
์ด์ฒ๋ผ ์์ ๋ณด๋ค ๋ณํ๊ธฐ ์ฌ์ด ๊ฒ์ ์์กดํ๋ ๊ฒ์ ์ถ์ํ๋ ์ธํฐํ์ด์ค๋ ์์ ํด๋์ค๋ฅผ ๋์ด ๋ณํ๊ธฐ ์ฌ์ด ๊ฒ์ ๋ณํ์ ์ํฅ๋ฐ์ง ์๊ฒ ํ๋ ๊ฒ์ด ์์กด ์ญ์ ์์น์ด๋ค.
์์ ํด๋์ค์ผ์๋ก, ์ธํฐํ์ด์ค์ผ์๋ก, ์ถ์ ํด๋์ค์ผ์๋ก ๋ณํ์ง ์์ ๊ฐ๋ฅ์ฑ์ด ๋๊ธฐ์ ํ์ ํด๋์ค๋ ๊ตฌ์ฒด ํด๋์ค๊ฐ ์๋ ์์ ํด๋์ค, ์ธํฐํ์ด์ค, ์ถ์ ํด๋์ค๋ฅผ ํตํด ์์กดํ๋ผ๋ ๊ฒ์ด๋ค.
๊ทธ๋ฐ๋ฐ ๊ฒฐ๊ตญ ์ด ๋ง์ ์ถ์ํ๋ฅผ ์ด์ฉํ๋ผ๋ ๋ง๊ณผ ์ผ๋งฅ์ํต ํ ๊ฒ ๊ฐ์๋ฐ, ์ฌ์ค ์์กด ์ญ์ ์ญ์น์ ์ฐ๋ฆฌ๊ฐ ์์ ๋ฐฐ์ด ๊ฐ๋ฐฉ-ํ์ ์์น๊ณผ ๊ธด๋ฐํ ๊ด๊ณ๊ฐ ์๋ค.
DIP ์์น ์๋ฐ ์์ ์ ์์ ํ๊ธฐ
์ด๋ฒ์ RPG ๊ฒ์ ์ฅ๋ฅด๋ฅผ ์์ ๋ก ๋ค์ด DIP ์ค๊ณ ์์น์ ๋ํด ์ดํดํด๋ณด์.
RPG ๊ฒ์์๋ ์บ๋ฆญํฐ๊ฐ ์ฅ์ฐฉํ ์ ์๋ ๋ค์ํ ๋ฌด๊ธฐ๋ค์ด ์กด์ฌํ๋ค. ๋ค์๊ณผ ๊ฐ์ด ํ์๊ฒ, ์์๊ฒ, ์ ํฌ๋๋ผ, ๋ง์น ํด๋์ค๊ฐ ์๋ค๊ณ ๊ฐ์ ํ์.
class OneHandSword {
final String NAME;
final int DAMAGE;
OneHandSword(String name, int damage) {
NAME = name;
DAMAGE = damage;
}
int attack() {
return DAMAGE;
}
}
class TwoHandSword {
// ...
}
class BatteAxe {
// ...
}
class WarHammer {
// ...
}
๊ทธ๋ฆฌ๊ณ ์ด๋ฌํ ๋ฌด๊ธฐ๋ค์ ์ฅ์ฐฉํ Character ํด๋์ค๊ฐ ์๋ค.
์ด ์บ๋ฆญํฐ ํด๋์ค๋ ์ธ์คํด์คํ๋ ๋ ์บ๋ฆญํฐ ์ด๋ฆ๊ณผ ์ฒด๋ ฅ ๊ทธ๋ฆฌ๊ณ ์ฅ์ฐฉํ๊ณ ์๋ ๋ฌด๊ธฐ๋ฅผ ์ ๋ ฅ๊ฐ์ผ๋ก ๋ฐ์ ์ด๊ธฐํ ํ๋ค.
ํ์๊ฒ๋ ํ๊ฐ์ง๋ง ์๋๊ฒ ์๋๋ผ ๊ฐ์ฒ ๊ฒ, ๋ฏธ์ค๋ฆด๊ฒ ๊ฐ์ด ๋ค์ํ ํ์
์ ๊ฒ์ด ์ฌ์ ์๊ธฐ ๋๋ฌธ์ ์บ๋ฆญํฐ ํด๋์ค๋ด์ ํ๋ ๋ณ์๋ก์ OneHandSword ํด๋์ค ํ์
์ ๋ณ์๋ฅผ ์ ์ฅํด๋๊ณ , attack() ๋ฉ์๋๋ฅผ ์ํํ๋ฉด OneHandSword ํด๋์ค์ ๋ฉ์๋๊ฐ ์คํ๋์ด ๋ฐ๋ฏธ์ง๊ฐ ๊ฐํ๋ ํํ์ด๋ค.
์ฆ, Character์ ์ธ์คํด์ค ์์ฑ ์ OneHandSword์ ์์กด์ฑ์ ๊ฐ์ง๊ธฐ๊ฒ๋์ด, ๊ณต๊ฒฉ ๋์์ ๋ด๋นํ๋ attack() ๋ฉ์๋ ์ญ์ OneHandSword์ ์์กด์ฑ์ ๊ฐ์ง๊ฒ ๋๊ฒ ๋๋ค.

class Character {
final String NAME;
int health;
OneHandSword weapon; // ์์กด ์ ์์ค ๊ฐ์ฒด
Character(String name, int health, OneHandSword weapon) {
this.NAME = name;
this.health = health;
this.weapon = weapon;
}
int attack() {
return weapon.attack(); // ์์กด ๊ฐ์ฒด์์ ๋ฉ์๋๋ฅผ ์คํ
}
void chageWeapon(OneHandSword weapon) {
this.weapon = weapon;
}
void getInfo() {
System.out.println("์ด๋ฆ: " + NAME);
System.out.println("์ฒด๋ ฅ: " + health);
System.out.println("๋ฌด๊ธฐ: " + weapon);
}
}
ํ์ง๋ง ๋ฌด๊ธฐ์ ํ์๊ฒ ํ์ ๋ง ์๋ ๊ฒ ์๋๋ค.
์์์ ์ดํด๋ดค๋ฏ์ด ์์๊ฒ, ์ ํฌ๋๋ผ, ๋ง์น ํ์ ์ ์ฌ๋ฌ ๋ฌด๊ธฐ๋ค์ ์ฅ์ฐฉํ๊ฒ ํ๋ ค๋ฉด, ์์ ์บ๋ฆญํฐ ํด๋์ค์ ํด๋์ค ํ๋ ๋ณ์ ํ์ ์ ๊ต์ฒดํด์ค์ผ ํ๋ค.
ํ์ง๋ง ๋ง์ฝ ์ ์ฝ๋๊ฐ ์์กด์ฑ ์ญ์ ์์น์ ์ ์ง์ผฐ๋ค๋ฉด ๊ณ ๋ฏผํ ํ์๊ฐ ์๋ ๋ฌธ์ ๋ค.
์ ์ฝ๋์ ๋ฌธ์ ๋ ์ด๋ฏธ ์์ ํ๊ฒ ๊ตฌํ๋ ํ์ ๋ชจ๋์ ์์กดํ๊ณ ์๋ค๋ ์ ์ด๋ค.
์ฆ, ๊ตฌ์ฒด ๋ชจ๋์ ์์กดํ๋ ๊ฒ์ด ์๋ ์ถ์์ ์ธ ๊ณ ์์ค ๋ชจ๋์ ์์กดํ๋๋ก ๋ฆฌํฉํ ๋ง ํ๋ฉด ๋๋ค.
์ฐ์ ๋ชจ๋ ๋ฌด๊ธฐ๋ค์ ํฌํจํ ์ ์๋ ๊ณ ์์ค ๋ชจ๋์ธ Weaponable ์ธํฐํ์ด์ค๋ฅผ ์์ฑํ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ชจ๋ ๊ณต๊ฒฉ ๊ฐ๋ฅํ ๋ฌด๊ธฐ ๊ฐ์ฒด๋ ์ด ์ธํฐํ์ด์ค๋ฅผ implements ํ๊ฒ ํ๋ค.

// ๊ณ ์์ค ๋ชจ๋
interface Weaponable {
int attack();
}
class OneHandSword implements Weaponable {
final String NAME;
final int DAMAGE;
OneHandSword(String name, int damage) {
NAME = name;
DAMAGE = damage;
}
public int attack() {
return DAMAGE;
}
}
class TwoHandSword implements Weaponable {
// ...
}
class BatteAxe implements Weaponable {
// ...
}
class WarHammer implements Weaponable {
// ...
}
๊ทธ๋ฆฌ๊ณ Character ํด๋์ค์ ๊ธฐ์กด์ OneHandSword ํ์ ์ ํ๋ ๋ณ์๋ฅผ ์ข ๋ ๊ณ ์์ค ๋ชจ๋์ธ Weaponable ์ธํฐํ์ด์ค ํ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ค.
๊ฒ์ ์์คํ ๋ด๋ถ์ ์ผ๋ก ๋ชจ๋ ๊ณต๊ฒฉ ๊ฐ๋ฅํ ๋ฌด๊ธฐ๋ Weaponable ์ ๊ตฌํํ๊ธฐ๋ก ๊ฐ์ ํ์ผ๋ฏ๋ก, ๊ณต๊ฒฉ ๊ฐ๋ฅํ ๋ชจ๋ ๋ฌด๊ธฐ๋ฅผ ํ ๋น ๋ฐ์ ์ ์๊ฒ ๋ ๊ฒ์ด๋ค.
class Character {
final String NAME;
int health;
Weaponable weapon; // ์์กด์ ๊ณ ์์ค์ ๋ชจ๋๋ก
Character(String name, int health, Weaponable weapon) {
this.NAME = name;
this.health = health;
this.weapon = weapon;
}
int attack() {
return weapon.attack();
}
void chageWeapon(Weaponable weapon) {
this.weapon = weapon;
}
void getInfo() {
System.out.println("์ด๋ฆ: " + NAME);
System.out.println("์ฒด๋ ฅ: " + health);
System.out.println("๋ฌด๊ธฐ: " + weapon);
}
}
์ด์ฐ๋ณด๋ฉด ์ด๋ฌํ DIP ์์น์ ๋ฐ๋ฆ์ผ๋ก์จ, ๋ฌด๊ธฐ์ ๋ณ๊ฒฝ์ ๋ฐ๋ผ Character์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ ํ์๊ฐ ์๊ณ ๋๋ค๋ฅธ ํ์ ์ ๋ฌด๊ธฐ ํ์ฅ์๋ ๋ฌด๋ฆฌ๊ฐ ์์ผ๋ OCP ์์น ๋ํ ์ค์ํ ๊ฒ์ด๋ผ๊ณ ๋ณผ์๋ ์๋ค.
# ์ฐธ๊ณ ์๋ฃ
https://www.nextree.co.kr/p6960/
https://youtu.be/DYmtue0k1cc
https://youtu.be/4ha2hUPMsFg
https://blog.itcode.dev/posts/2021/08/17/dependency-inversion-principle
์ด ๊ธ์ด ์ข์ผ์ จ๋ค๋ฉด ๊ตฌ๋ & ์ข์์
์ฌ๋ฌ๋ถ์ ๊ตฌ๋
๊ณผ ์ข์์๋
์ ์์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค.