SOLID
Robert C. Martin ์ด 2000๋ ๋ ์ด ๋ช ๋ช ํ ๊ฐ์ฒด์งํฅ์ ๋ค์ฏ๊ฐ์ง ํ๋ก๊ทธ๋๋ฐ ๋ฐ ์ค๊ณ์ ์์น๋ค์ ๋๋ฌธ์์ด ๊ธฐ์ต์ ๋ก ์๊ฐํ๊ฒ์ด๋ค.
์ด๋ ๊ฐ์ฒด์งํฅ 4๋ ํน์ฑ์ธ ์บก์ํ, ์์, ์ถ์ํ, ๋คํ์ฑ ๋ฑ์ ์ด์ฉํ์ฌ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ ์ค๊ณ๋ฅผ ๋์์ฃผ๋ ์์น๋ค์ด ์๋ค.
์๊ธฐ ์์ ์ ํด๋์ค์ ์์ง๋๋ฅผ ๋์ด๊ณ , ํ ํด๋์ค์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๋ (High-Cohesion - Loose Coupling) ์์น์ ๊ฐ์ฒด ์งํฅ๊ด์ ์์ ๋์ ํ๊ฒ์ด๋ค.
SOLID 5๋ ์์น (๊ฐ์ฒด ์งํฅ ์ค๊ณ 5์์น)
- SRP (Single Reponsibility Principle : ๋จ์ผ ์ฑ ์์ ์์น)
- OCP (Open Closed Principle : ๊ฐ๋ฐฉ ํ์์ ์์น)
- LSP (Liskov Substitution Principle : ๋ฆฌ์ค์ฝํ ์นํ์ ์์น)
- ISP (Interface Segregation Principle : ์ธํฐํ์ด์ค ๋ถ๋ฆฌ์ ์์น)
- DIP (Dependency Inversion Principle : ์์กด ์ญ์ ์ ์์น)
๋จ์ผ ์ฑ ์์ ์์น (SRP : Single Reponsibility Principle)
์์ฑ๋ ํด๋์ค๋ ํ๋์ ๊ธฐ๋ฅ๋ง ๊ฐ์ง๋ฉฐ ํด๋์ค๊ฐ ์ ๊ณตํ๋ ๋ชจ๋ ์๋น์ค๋ ๊ทธ ํ๋์ ์ฑ ์์ ์ํํ๋๋ฐ ์ง์ค ๋์ด์ผ ํ๋ค๋๊ฒ
- ์ํํธ์จ์ด์ ์ค๊ณ ๋ถํ (ํด๋์ค, ํจ์) ๋ ๋จ ํ๋์ ์ฑ ์ (๊ธฐ๋ฅ) ๋ง ๊ฐ์ ธ์ผ ํ๋ค.
์๋ก์ด ์๊ตฌ์ฌํญ์ ๋ํด ํ๋ก๊ทธ๋จ์ด ์ํฅ ๋ฐ๋ ๋ถ๋ถ์ด ์ ์ด์ผ ํ๋ค. ๋ค์ ๋งํ๋ฉด ์์ง๋๋ ๋๊ณ ๊ฒฐํฉ๋๋ ๋ฎ์์ผ ํ๋ค ๋ผ๋ ๋ง์ด๋ค.
๋ง์ฝ ํ ํ๋ก๊ทธ๋จ์ด ์ฑ
์(๊ธฐ๋ฅ์ ๋ด๋น) ์ง๊ณ ์๋ ๋ถ๋ถ์ด ๋ง์์ง๋ฉด ํด๋์ค ๋ด๋ถ์ ํจ์๋ผ๋ฆฌ ๊ฐํ ๊ฒฐํฉ๋๋ฅผ ๊ฐ์ง์ ์๋ ๊ฐ๋ฅ์ฑ์ด ๋๊ธฐ ๋๋ฌธ์ ์๊ตฌ์ฌํญ์ ์์ ์ด ๋ฐ์ํ ๊ฒฝ์ฐ ์ ์ง๋ณด์ ๋น์ฉ์ด ์ฆ๊ฐํ๋ค.
๋ฐ๋ผ์ ์ฑ
์ (๊ธฐ๋ฅ) ์ ๋ถ๋ฆฌ ํ ์ ์๋ ๊ตฌ์กฐ๋ก ์ค๊ณ๋์ด์ผ ํ๋ค.
๋ฆฌํฉํ ๋ง (Refactoring) ์ ํตํ์ฌ ํด๋น ์ฑ ์์ ์ต์์ ์ํ๋ก ๋ถ๋ฐฐ
๊ฐ๋ฐฉ ํ์ ์์น (OCP : Open Closed Principle)
์ํํธ์จ์ด์ ๊ตฌ์ฑ์์ (์ปดํฌ๋ํธ, ํด๋์ค, ๋ชจ๋, ํจ์) ๋ ํ์ฅ์๋ ์ด๋ ค ์๊ณ , ๋ณ๊ฒฝ์๋ ๋ซํ ์์ด์ผ ํ๋ค๋ ์๋ฏธ์ด๋ค.
๊ธฐ์กด์ ๊ตฌ์ฑ์์๋ ์์ ์ด ์ผ์ด๋์ง ๋ง์์ผ ํ๋ฉฐ, ๊ธฐ์กด์ ๊ตฌ์์์๋ฅผ ์ฝ๊ฒ ํ์ฅํ์ฌ ์ฌ ์ฌ์ฉ ๊ฐ๋ฅํด์ผ ํ๋ค๋ ๋ป์ด๋ค.
- ํ์ฅ ๋ ๊ฒ๊ณผ ๋ถ๋ณ์ ์์ฑ์ ์๊ฒฉํ ๊ตฌ๋ถํ๋ค.
- ๋ ๋ชจ๋์ด ๋ง๋๋ ์ง์ ์ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ๋ค.
- ๊ตฌํ์ ์์กดํ๊ธฐ๋ณด๋ค ์ ์ํ ์ธํฐํ์ด์ค์ ์์กดํ๋๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ค.
์ ์
- ์ํํธ์จ์ด์ ๊ตฌ์ฑ์์ (์ปดํฌ๋ํธ, ํด๋์ค, ๋ชจ๋, ํจ์) ๋ ํ์ฅ์๋ ์ด๋ ค ์๊ณ , ๋ณ๊ฒฝ์๋ ๋ซํ ์์ด์ผ ํ๋ค.
์ด๋ ๊ธฐ์กด์ ๊ตฌ์ฑ์์๋ ์์ ์ด ์ผ์ด๋์ง ๋ง์์ผ ํ๋ฉฐ, ๊ธฐ์กด์ ๊ตฌ์ฑ์์๋ฅผ ์ฝ๊ฒ ํ์ฅํ์ฌ ์ฌ์ฌ์ฉ ๊ฐ๋ฅ ํด์ผ ํ๋ค๋ ๋ป์ด๋ฉฐ, ํ๋ก๊ทธ๋จ ์ค๊ณ ๊ณผ์ ์์ ๋ง์ ๊ณ ๋ฏผ์ด ๋์ด ์์ด์ผ ํ๊ณ ์ด๋ฅผ ์ํด ์์ฃผ ์ฌ์ฉ๋๋ ๋ฌธ๋ฒ์ด interface
๋ฅผ ํ์ฉํ ๋ฐฉ๋ฒ์ด๋ค.
์๋ ์์๋ฅผ ํตํ์ฌ OCP ์ ์๋ฐฐ ์ฌํญ์ ์ดํด ๋ณด์
class SoundPlayer {
void play() {
System.out.println("play wav");
}
}
public class Client {
public static void main(String[] args) {
SoundPlayer sp = new SoundPlayer();
sp.play();
}
}
์๊ธฐ ์ฝ๋์์ play()
๋ฅผ ๋ค๋ฅธ ํ์ผ ํฌ๋งท์ ์ฌ์์ ์ํ๋ค๋ฉด OCP ์์น์ ์๋ฐฐ๋๋ค.
์ด๋ฌํ ๊ฒฝ์ฐ์๋ interface
๋ฅผ ๊ตฌ์ฑํ์ฌ OCP ๋ฅผ ๋ง์กฑํ๋ค.
interface playAlgorithm {
public void play();
}
class Wav implements playAlgorithm {
@Override
public void play() {
System.out.println("Play Wav");
}
}
class Mp3 implements playAlgorithm {
@Override
public void play() {
System.out.println("Play Mp3");
}
}
์์ ๊ฐ์ด ์ฌ์ํ๊ณ ์ ํ๋ playAlgorithm
์ธํฐํ์ด์ค์ play()
๋ฅผ ์ฌ์ ์ ํ๋๋ก ์ค๊ณํ๋ค.
์ด์ ๊ฐ์ ์ค๊ณ ๋ฐฉ์์ ๋์์ธ ํจํด์์๋ ์ ๋ต ํจํด (Strategy Pattern) ์ด๋ผ๊ณ ํ๋ค.
OCP ๋ฅผ ๋ง์กฑํ ์ค๊ณ๋ ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ด ์๋ค.
- ๋ณ๊ฒฝ์ ์ ์ฐํ๊ฒ ๋์ฒ ๊ฐ๋ฅํ๋ค.
- ์ ์ง๋ณด์ ๋น์ฉ์ด ๊ฐ์๋๋ค.
- ์ฝ๋์ ๊ฐ๋ ์ฑ์ด ๋์์ง๋ค.
๋ฆฌ์ค์ฝํ ์นํ ์์น (LSP : Liskov Substitution Principle)
OCP (Open Close Principle : ๊ฐ๋ฐฉ ํ์ ์ ๋ฒ์น) ๊ณผ ๋ฐ์ ํ ์ฐ๊ด์ด ์์ผ๋ฉฐ OCP ๋ฅผ ๋ฐํ์ผ๋ก ๊ตฌํํ ํ
ํ๋ฆญ ์ค๊ณ์ ํ๋์ ์๋ผ๊ณ ํ ์ ์๋ค.
์ฆ LSP ๋ OCP ์ ํด๊ฒฐ์ฑ
์ค ํ๋์ด๋ค.
์ ์
- ์์ (ํ์) ํด๋์ค๋ ์ธ์ ๋ ๋ถ๋ชจ (๊ธฐ๋ฐ) ํ์ ๊ณผ ํธํ์ด ๋์ด์ผ ํ๋ค.
- ์๋ธํ์ ์ ์ธ์ ๋ ๊ธฐ๋ฐ ํ์ ๊ณผ ํธํ๋ ์ ์์ด์ผ ํ๋ค.
- ํ์ ํด๋์ค๊ฐ ์์ ํด๋์ค์ ์ญํ ์ ๋์ ํ ๋ ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ง์ ๋จ์ด์ ธ์ผ ํ๋ค.
๋ค์ ์๋ ์ด๋ฅผ ์ค๋ช ํ๊ธฐ ์ํ ๊ฐ์ฅ ์ ๋ช ํ ์ ์ด๋ค.
์ต์ด์ ๊ธฐ๋ฐํ์
์ ๋ด๋นํ Rectagle
ํด๋์ค๋ฅผ ์ ์ธํ๋ค.
์ฌ๊ธฐ์๋ ๋๋น์ ๋์ด ๋ฑ์ด ์ ์ธ๋์ด ์์ผ๋ฉฐ ๋ํ์ ๋์ด๋ฅผ ๋ฐํํ๋ area
ํจ์๊น์ง ๊ตฌํ๋์ด ์๋ค.
class Rectangle {
private int width;
private int height;
public void setHeight(int height) {
this.height = height;
}
public int getHeight() {
return this.height;
}
public void setWidth(int width) {
this.width = width;
}
public int getWidth() {
return this.width;
}
public int area() {
return this.width * this.height;
}
}
Rectangle
ํด๋์ค๋ฅผ ์์ ๋ฐ๋ Square
ํด๋์ค๊ฐ ์๋ค.
Square
ํด๋์ค๋ ์ ์ฌ๊ฐํ ์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ๋ด๋นํ๋ ํด๋์ค์ด๋ค.
class Square extends Rectangle {
@Override
public void setHeight(int value) {
this.width = value;
this.height = value;
}
@Override
public void setWidth(int value) {
this.width = value;
this.height = value;
}
}
์์ ๋๊ฐ์ ํด๋์ค๋ฅผ ์๋นํ ๋ฉ์ธ ํจ์์ด๋ค.
public class MyClass {
static boolean checkAreaSize(Rectangle r) {
r.setWidth(5);
r.setHeight(4);
if (r.area() != 20 ) {
throw new RuntimeException("Bad Area");
}
return true
}
public static void main(String[] args) {
checkAreaSize(new Rectangle());
checkAreaSize(new Square()); // Error Exception
}
}
์ด๋ฅผ ์คํํ๋ฉด ๋๊ฐ์ ํด๋์ค๊ฐ ์ ํ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์จ๋ค.
ํ๋๋ Rectangle
ํด๋์ค๋ ๋์ด๊ฐ 20 ์ผ๋ก ์ฐ์ฐ ๋๋๋ฐ ๋ฐํด Square
ํด๋์ค๋ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ค.
์ด๊ฒ์ด ๋ฐ๋ก ๋ฆฌ์ค์ฝํ์ ์นํ ์์น ์ ๋ฒ์ด๋ ๋ํ์ ์ธ ์์ด๋ค.
๋ค์ ์ ๋ฆฌํ๋ฉด ์์ ํ์ ์ ๊ฐ์ฒด๋ฅผ ํ์ํ์ ์ ๊ฐ์ฒด๋ก ์นํํด๋ ์์ ํ์ ์ ์ฌ์ฉํ๋ ํ๋ก๊ทธ๋จ์ ์ ์์ ์ผ๋ก ๋์ ํด์ผ ํ๋ค.
๋ฆฌ์ค์ฝํ ์นํ์ ๋ฒ์ด๋๋ ์๋ฐ์ฌ๋ก๋ ๋ํ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ๋ค.
- ๋ช ์๋ ๋ช ์ธ์์ ๋ฒ์ด๋ ๊ฐ ์ ๋ฐํํ๋ค.
- ๋ช ์๋ ๋ช ์ธ์์ ๋ฒ์ด๋ ์ค๋ฅ ๋ฅผ ๋ฐ์ํ๋ค.
- ๋ช ์๋ ๋ช ์ธ์์ ๋ฒ์ด๋ ๊ธฐ๋ฅ ์ ์ํํ๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
- ์์๊ด๊ณ๋ฅผ ์ ๊ฑฐํ๋ค.
- ๋ฌธ์ ๊ฐ ๋๋
area()
๋ฅผSquare
๋ก ์ด๋ํ๋ค. - LSP ๋ฅผ ํตํ์ฌ ์์ ํด๋์ค๊ฐ ์์๋ฐ์ ๋ถ๋ชจ ํด๋์ค์ ์ญํ์ ์ถฉ์คํ ํ๋ฉด์ ํ์ฅ ํด๋๊ฐ์ผ ํ๋ค.
์ฐธ๊ณ ์๋ฃ
์ธํฐํ์ด์ค ๋ถ๋ฆฌ ์์น (ISP : Interface Segregation Principle)
์ต์ํ์ ์๋ฏธ์ ๋ง๋ ์ธํฐํ์ด์ค๋ง ๊ตฌํํด์ผ ํ๋ค.
- ํ๋์ ํด๋์ค๋ ์์ ์ด ์ฌ์ฉํ์ง ์๋ ์ธํฐํ์ด์ค๋ ๊ตฌํํ์ง ์์์ผ ํ๋ค.
- ํ๋์ ์ธํฐํ์ด์ค๋ณด๋ค๋ ์ฌ๋ฌ๊ฐ์ ๊ตฌ์ฒด์ ์ธ ์ธํฐํ์ด์ค๊ฐ ๋ซ๋ค
์์คํ ์ ๋ด๋ถ ์์กด์ฑ์ ์ฝํ์์ผ ๋ฆฌํํ ๋ง, ์์ , ์ฌ๋ฐฐํฌ๋ฅผ ์ฝ๊ฒํ ์ ์๋ค.
์์กด ์ญ์ ์์น (DIP : Dependency Inversion Principle)
ํ์ ๋ ๋ฒจ๋ชจ๋์ ๋ณ๊ฒฝ์ด ์์ ๋ ๋ฒจ ๋ชจ๋์ ๋ณ๊ฒฝ์ ์๊ตฌํ๋ ์ญ์ ํ์
- ์์กด ๊ด๊ณ๋ฅผ ๋งบ์ ๋, ๋ณํํ๊ธฐ ์ฌ์ด๊ฒ (ํด๋์ค) ๋ณด๋จ ๋ณํํ๊ธฐ ์ด๋ ค์ด ๊ฒ (์ถ์ํด๋์ค, ์ธํฐํ์ด์ค) ์ ์์กดํด์ผ ํ๋ค
Policy policy = new UrlPolicyImpl();
new Factory(policy);
์์ ๊ฐ์ด ๊ตฌ์ ํด๋์ค์ ์์กดํ๋๊ฑธ ์ถ์ํด๋์ค์ ์์กดํ๋ ๊ฒ์ด๋ค.
UrlPolicyImpl
ํด๋์ค๋ Policy
์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋๋ฐ new Factory(policy);
์ ๊ฐ์ด ์ค์ ๋ก Policy
์ธํฐํ์ด์ค์๊ฒ ์์กดํ์ฌ ์ด๊ธฐํ๋ฅผ ํ๋ค.
์ด๋ ๋ณํํ๊ธฐ ์ฌ์ด ์ค์ ๊ตฌํ ํด๋์ค UrlPolicyImpl
๋ณด๋ค Policy
์ธํฐํ์ด์ค์๊ฒ ์์กดํจ์ผ๋ก์จ ์์ ์ ์ผ๋ก ๊ฐ์ ธ๊ฐ ์ ์๋ค.
โ Polymorphism Immutable Class โ