SOLID

๋ž ๋œจยท2025๋…„ 7์›” 11์ผ

๐Ÿ”Ž Overview

ย  ์Šคํ”„๋ง์˜ ์›๋ฆฌ๋ฅผ ๊ณต๋ถ€ํ•˜๋˜ ๋„์ค‘, ์ต์ˆ™ํ•œ ๋‹จ์–ด๊ฐ€ ๋‚˜์™”๋‹ค. SOLID , ์ข‹์€ ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„์˜ 5๊ฐ€์ง€ ์›์น™์ด๋‹ค.
๊ธฐ์กด์—๋„ ๋‹น์—ฐํžˆ ์•Œ๊ณ  ์žˆ๋˜ ๊ฐœ๋…์ด์ง€๋งŒ ์‚ฌ์‹ค์ƒ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ๋‹จ์ˆœํžˆ ์™ธ์šฐ๊ณ ๋งŒ ์žˆ์—ˆ๋˜ ๊ฐœ๋…์ด์—ˆ์œผ๋ฏ€๋กœ, ํ™•์‹คํ•˜๊ฒŒ ์•Œ๊ณ  ์žˆ๋‹ค๊ณ ๋Š” ๋‹จ์ •ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค.
SOLID ๋Š” ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๋ฐ˜๋“œ์‹œ ์•Œ๊ณ  ์‹ค๋ฌด์—์„œ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฐœ๋…์ด๋‹ค. ์ด๋ฒˆ ๊ธฐํšŒ์—, ๋ณด๋‹ค ์ข‹์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋  ์ˆ˜ ์žˆ๋„๋ก SOLID ์— ๋Œ€ํ•œ ํ™•์‹คํ•œ ์ดํ•ด๋ฅผ ๋ชฉํ‘œ๋กœ ํ•™์Šต ๋ฐ ์ •๋ฆฌํ•ด๋ณด์•˜๋‹ค.


๐Ÿ“• SOLID

  • ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐ ์„ค๊ณ„์—์„œ ์‚ฌ์šฉ๋˜๋Š” 5๊ฐ€์ง€ ๊ธฐ๋ณธ ์›์น™
  • ์†Œํ”„ํŠธ์›จ์–ด์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ, ๊ฐ€๋…์„ฑ, ํ™•์žฅ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ


๐Ÿ“Œ 5๊ฐ€์ง€ ์›์น™

1๏ธโƒฃ SRP (Single Responsibility Principle)

  • ๋‹จ์ผ ์ฑ…์ž„ ์›์น™
  • ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋Š” ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ๊ฐ€์ ธ์•ผ ํ•จ
    • ์ฑ…์ž„์€ ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์ด๋ผ๊ธฐ๋ณด๋‹ค๋Š”, ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•  ๋‹จ ํ•˜๋‚˜์˜ ์ด์œ 
    • ์—ฌ๋Ÿฌ ์ด์œ ๋กœ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด SRP ์œ„๋ฐ˜
    • ํ•œ ๊ฐ€์ง€ ์ฑ…์ž„์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋„๋ก, ํด๋ž˜์Šค๋ฅผ ์ ์ ˆํžˆ ๋ถ„๋ฆฌํ•ด์„œ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์›์น™
  • ์ฑ…์ž„์˜ ๊ธฐ์ค€ ๋ฐ ๋ฒ”์œ„๋Š” ๊ฐœ๋ฐœ์ž๋งˆ๋‹ค ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ
    • MemberService ์— ํšŒ์› ๋„๋ฉ”์ธ์— ๋Œ€ํ•œ ๋กœ์ง์„ ๋ชจ์•„๋‘์–ด๋„ (ํ•˜๋‚˜์˜ ํด๋ž˜์Šค์— ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ๋งŒ ์กด์žฌํ•˜์ง€ ์•Š๋”๋ผ๋„), ํšŒ์›์ด๋ผ๋Š” ์ผ๊ด€๋œ ์ฑ…์ž„ ๋‚ด์—์„œ ๋™์ž‘ํ•˜๋ฏ€๋กœ SRP ์œ„๋ฐ˜์ด ์•„๋‹˜
// SRP ์œ„๋ฐ˜
public class memberService {
	public void join(Member member) {
    	// ํšŒ์› ์ €์žฅ
    }
    
    public void sendMail(Member member) {
    	// ์ด๋ฉ”์ผ ๋ฐœ์†ก
    }
}
  • ํšŒ์› ์ €์žฅ๊ณผ ์ด๋ฉ”์ผ ๋ฐœ์†ก์ด๋ผ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๊ฐ€์ง€ ์ฑ…์ž„์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ, SRP ์œ„๋ฐ˜
// SRP ์ค€์ˆ˜
public class MemberService {
	public void join(Member member) {
    	// ํšŒ์› ์ €์žฅ
    }
}

public class EmailService {
	public void sendMail(Member member) {
    	// ์ด๋ฉ”์ผ ๋ฐœ์†ก
    }
}
  • MemberService ๋Š” ํšŒ์› ๋„๋ฉ”์ธ์—๋งŒ, EmailService ๋Š” ์ด๋ฉ”์ผ ๋„๋ฉ”์ธ์—๋งŒ ์ง‘์ค‘ํ•˜๋ฏ€๋กœ, SRP ์ค€์ˆ˜

2๏ธโƒฃ OCP (Open Closed Principle)

  • ๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™
  • ์†Œํ”„ํŠธ์›จ์–ด๋Š” ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ  ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ์–ด์•ผ ํ•จ
    • ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๋ฐ ๋ณ€๊ฒฝ ์‹œ ํด๋ž˜์Šค ํ™•์žฅ์„ ํ†ตํ•ด ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋˜, ๊ธฐ์กด ํด๋ž˜์Šค์˜ ์ˆ˜์ •์€ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„
    • ์—ญํ• ๊ณผ ๊ตฌํ˜„์˜ ๋ถ„๋ฆฌ
  • ๋‹คํ˜•์„ฑ์„ ํ™œ์šฉ
    • ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•˜๊ณ , ์ •์ฑ…์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ ๊ตฌํ˜„์ฒด๋ฅผ ์ œ๊ณต
    • ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์žฅ์ ์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ์Œ
  • ์Šคํ”„๋ง์€ IOC ๋ฐ DI ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์›์น™์„ ์ค€์ˆ˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์–ด์žˆ์Œ
// OCP ์œ„๋ฐ˜
public class DiscountService {
	public int getNormalDiscountRate() {
    	// ํ• ์ธ์œจ ๋กœ์ง
    }
}
  • VIP , GOLD ๋“ฑ ์ƒˆ๋กœ์šด ์ •์ฑ… ์ถ”๊ฐ€ ์‹œ ํด๋ž˜์Šค ์ˆ˜์ • ํ•„์š”
// OCP ์ค€์ˆ˜
public interface DiscountPolicy{
	int getDiscountRate();
}

public class VipDiscountPolicy implements DiscountPolicy {
	public int getDiscountRate() {
    	// VIP ํ• ์ธ์œจ ๋กœ์ง
    }
}

public class NormalDiscountPolicy implements DiscountPolicy {
	public int getDiscountRate() {
    	// ์ผ๋ฐ˜ ํ• ์ธ์œจ ๋กœ์ง
    }
}

public class DiscountService {
	private final DiscountPolicy discountPolicy;
    
    public DiscountService(DiscountPolicy discountPolicy) {
    	this.discountPolicy = discountPolicy;
    }
    
    public int discount() {
    	return discountPolicy.getDiscountRate();
    }
}
  • ์ƒˆ ์ •์ฑ… ์ถ”๊ฐ€ ์‹œ, DiscountPolicy ๊ตฌํ˜„์ฒด๋งŒ ์ถ”๊ฐ€ํ•˜์—ฌ ์ฃผ์ž…ํ•˜๋ฉด ๋จ

3๏ธโƒฃ LSP (Liskov Substitution Principle)

  • ๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™
  • ํ•˜์œ„ ํƒ€์ž…์€ ์–ธ์ œ๋‚˜ ์ƒ์œ„ ํƒ€์ž…์œผ๋กœ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ
    • ๋‹คํ˜•์„ฑ์„ ์ œ๋Œ€๋กœ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์›์น™
    • ์ƒ์œ„ ํด๋ž˜์Šค ํƒ€์ž…์œผ๋กœ ํ•˜์œ„ ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ๋ฐ›๋”๋ผ๋„ (์—…์บ์ŠคํŒ…), ๊ธฐ๋Šฅ์ด ์›ํ•˜๋Š”๋Œ€๋กœ ๋™์ž‘ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ
    • ๊ธฐ๋Šฅ์  ์˜๋ฏธ๋ฅผ ํ•ด์น˜๋Š”, ๋ถ€์ ์ ˆํ•œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์„ ํ•˜์ง€ ์•Š๋„๋ก ์„ค๊ณ„
    • ๋ถ€๋ชจ์˜ sleep() ์ด๋ผ๋Š” ์ž ์ž๋Š” ์˜๋ฏธ์˜ ๋ฉ”์„œ๋“œ๋ฅผ, ์ž์‹์ด ๋‹ฌ๋ฆฌ๊ธฐ๋ผ๋Š” ์˜๋ฏธ๋กœ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜๋ฉด LSP ์›์น™์„ ์œ„๋ฐ˜
// LSP ์œ„๋ฐ˜
class Parent {
	int[] location = {0, 0};
    
	void sleep() {
    	try {
    		Thread.sleep(1000);
        } catch (InterruptedException e) {}
    }
}

class Child extends Parent {
	@Override
    void sleep() {
    	location[0]++;
    }
}
  • ๋ถ€๋ชจ๋Š” ์“ฐ๋ ˆ๋“œ ๋Œ€๊ธฐ์˜ ์˜๋ฏธ๋กœ sleep() ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ, ์ž์‹์€ ์›€์ง์ด๊ธฐ์˜ ์˜๋ฏธ๋กœ sleep() ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ
    • ๋ฉ”์„œ๋“œ์˜ ์˜๋„์™€ ์˜๋ฏธ๊ฐ€ ์ „ํ˜€ ๋‹ฌ๋ผ์ง€๋ฏ€๋กœ LSP ์œ„๋ฐ˜
// LSP ์ค€์ˆ˜
class Parent {
	int[] location = {0, 0};
    
	void sleep() {
    	try {
    		Thread.sleep(1000);
        } catch (InterruptedException e) {}
    }
}

class Child extends Parent {
	@Override
	void sleep() {
    	try {
    		Thread.sleep(2000);
        } catch (InterruptedException e) {}
    }
}
  • ๋ถ€๋ชจ์™€ ์ž์‹ ๋ชจ๋‘ ์“ฐ๋ ˆ๋“œ ๋Œ€๊ธฐ์˜ ์˜๋ฏธ๋กœ sleep() ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„


4๏ธโƒฃ ISP (Interface Segregation Principle)

  • ์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ ์›์น™
  • ์ธํ„ฐํŽ˜์ด์Šค ํ•˜๋‚˜์— ๋งŽ์€ ๊ธฐ๋Šฅ์„ ๋‹ด๊ธฐ๋ณด๋‹ค๋Š”, ๊ฐ๊ฐ์˜ ์‚ฌ์šฉ์ฒ˜์— ๋งž๊ฒŒ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋ถ„๋ฆฌํ•ด์•ผ ํ•จ
    • SRP ๋Š” ํด๋ž˜์Šค ๋ถ„๋ฆฌ์˜ ์›์น™์ด๋ผ๋ฉด, ISP ๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ์˜ ์›์น™
  • ํŠน์ • ํด๋ผ์ด์–ธํŠธ๋ฅผ ์œ„ํ•ด ์ ํ•ฉํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ
  • ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ•œ ๋ฒˆ ๊ตฌ์„ฑํ•ด๋’€์œผ๋ฉด ์›ฌ๋งŒํ•ด์„œ๋Š” ๋ณ€๊ฒฝ์‹œํ‚ค๋ฉด ์•ˆ๋จ
  • ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋ณด๋‹ค ๋ช…ํ™•ํ•ด์ง€๊ณ , ๋Œ€์ฒด ๊ฐ€๋Šฅ์„ฑ์˜ ์ฆ๊ฐ€๋กœ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ
// ISP ์œ„๋ฐ˜
interface Machine {
	void print();
    void scan();
    void fax();
}

class PrintMachine implements Machine {
	public void print() {
    	// ํ”„๋ฆฐํŠธ
    }
    
    public void scan() {
    	throw new RuntimeException("์Šค์บ”์€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ");
    }
    
    public void fax() {
    	throw new RuntimeException("ํŒฉ์Šค๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ");
    }
}
  • PrintMachine ์€ ํ”„๋ฆฐํŠธ ๊ธฐ๋Šฅ๋งŒ ํ•„์š”ํ•˜์ง€๋งŒ, scan() , fax() ๋„ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ISP ์œ„๋ฐ˜
// ISP ์ค€์ˆ˜
interface Printer {
	void print();
}

interface Scanner {
	void scan();
}

class PrintMachine implements Printer {
	public void print() {
    	// ํ”„๋ฆฐํŠธ
    }
}
  • PrintMachine ์€ ํ”„๋ฆฐํŠธ์— ํ•„์š”ํ•œ Printer ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ๊ตฌํ˜„ํ•˜๋ฉด ๋จ

5๏ธโƒฃ DIP (Dependency Inversion Principle)

  • ์˜์กด๊ด€๊ณ„ ์—ญ์ „ ์›์น™
  • ๊ตฌ์ฒดํ™”์— ์˜์กดํ•ด์„  ์•ˆ๋˜๊ณ , ์ถ”์ƒํ™”์— ์˜์กดํ•ด์•ผ ํ•จ
    • ๊ตฌํ˜„ ํด๋ž˜์Šค์— ์˜์กดํ•˜์ง€ ๋ง๊ณ , ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•  ๊ฒƒ
    • ์—ญํ• ์— ์˜์กดํ•˜๋„๋ก ์„ค๊ณ„
    • ๋ณ€๊ฒฝ๋˜๊ธฐ ์‰ฌ์šด ๊ฒƒ๋ณด๋‹ค ๋ณ€๊ฒฝ๋˜๊ธฐ ์–ด๋ ค์šด ๊ฒƒ์— ์˜์กดํ•˜๋„๋ก ์„ค๊ณ„
  • ํด๋ž˜์Šค๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ
  • ์Šคํ”„๋ง์€ IOC ๋ฐ DI ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์›์น™์„ ์ค€์ˆ˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์–ด์žˆ์Œ
// DIP ์œ„๋ฐ˜
public class OrderService {
	private final DiscountPolicy discountPolicy = new VipDiscountPolicy();
    
    public int order() {
    	return discountPolicy.getDiscountRate();
    }
}
  • VipDiscountPolicy ์— ์˜์กดํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ๋‹ค๋ฅธ ์ •์ฑ…์œผ๋กœ ๋ณ€๊ฒฝ์„ ์›ํ•˜๋ฉด ํ•ด๋‹น ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์˜ ์ˆ˜์ •์ด ํ•„์š”
// DIP ์ค€์ˆ˜
public class OrderService {
	private final DiscountPolicy discountPolicy;
    
    public OrderService(DiscountPolicy discountPolicy) {
    	this.discountPolicy = discountPolicy;
    }
    
    public int order() {
    	return discountPolicy.getDiscountRate();
    }
}
  • ์™ธ๋ถ€์—์„œ DiscountPolicy ๊ตฌํ˜„์ฒด๋ฅผ ์ฃผ์ž…ํ•˜๋ฏ€๋กœ, ์ •์ฑ…์— ๋”ฐ๋ผ ์ž์œ ๋กญ๊ฒŒ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์Œ
  • ์Šคํ”„๋ง์—์„œ๋Š” @Component , @Autowired ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์ด ๊ตฌ์กฐ๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ ๊ฐ€๋Šฅ

์ฐธ๊ณ ) OpenAI. (2024).ChatGPT(4o)[Large language model].https://chatgpt.com/

profile
๊ธฐ๋ก

0๊ฐœ์˜ ๋Œ“๊ธ€