SOLID

ν΄λ¦°μ½”λ“œλ‘œ 유λͺ…ν•œ λ‘œλ²„νŠΈ λ§ˆν‹΄μ΄ μ •μ˜ν•œ 객체 μ§€ν–₯ μ„€κ³„μ˜ 5κ°€μ§€ 원칙

SRP: 단일 μ±…μž„ 원칙(Single Responsibility Principle)

  • ν•˜λ‚˜μ˜ ν΄λž˜μŠ€λŠ” ν•˜λ‚˜μ˜ μ±…μž„(λͺ©μ )만 κ°€μ Έμ•Ό ν•œλ‹€.

    • μ±…μž„μ€ 클 μˆ˜λ„ 있고, μž‘μ„ μˆ˜λ„ 있으며 상황에 따라 λ‹€λ₯΄λ‹€.

    • 클래슀λ₯Ό λ³€κ²½ν•˜λŠ” μ΄μœ κ°€ ν•˜λ‚˜μ˜ μ΄μœ μ—¬μ•Ό ν•œλ‹€.

  • 변경에 μš©μ΄ν•˜κ²Œ μ„€κ³„ν–ˆλ‹€λ©΄ 단일 μ±…μž„ 원칙을 잘 λ”°λ₯Έ 것

class Order {
    private List<Item> items;

    public void addItem(Item item) {
        // μ•„μ΄ν…œμ„ 주문에 μΆ”κ°€ν•˜λŠ” 둜직
    }

    public double calculateTotal() {
        // 주문의 총 가격을 κ³„μ‚°ν•˜λŠ” 둜직
    }
}

class Item {
    private String name;
    private double price;

    // μ•„μ΄ν…œμ˜ 이름과 가격을 μ„€μ •ν•˜λŠ” μƒμ„±μž 및 λ©”μ„œλ“œ
}

Order ν΄λž˜μŠ€λŠ” 주문에 κ΄€λ ¨λœ μ±…μž„λ§Œ κ°€μ§€κ³  있고, Item ν΄λž˜μŠ€λŠ” μ•„μ΄ν…œμ— κ΄€λ ¨λœ μ±…μž„λ§Œ κ°€μ§€κ³  μžˆλ‹€.

OCP: 개방-폐쇄 원칙 (Open-Closed principle)

  • ν™•μž₯μ—” μ—΄λ €μžˆμœΌλ‚˜, λ³€κ²½μ—λŠ” λ‹«ν˜€μžˆμ–΄μ•Ό ν•œλ‹€.

  • μƒˆλ‘œμš΄ κΈ°λŠ₯을 μΆ”κ°€ν•  λ•Œ κΈ°μ‘΄ μ½”λ“œλ₯Ό λ³€κ²½ν•˜μ§€ μ•Šκ³  ν™•μž₯ν•  수 μžˆλ„λ‘ 섀계해야 ν•œλ‹€.

interface Shape {
    double calculateArea();
}

class Circle implements Shape {
    private double radius;

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

class Rectangle implements Shape {
    private double width;
    private double height;

    @Override
    public double calculateArea() {
        return width * height;
    }
}

// 쒋은 예, κΈ°μ‘΄ μ½”λ“œλ₯Ό λ³€κ²½ν•˜μ§€ μ•Šκ³  ν™•μž₯ κ°€λŠ₯
class Test1 {
    private Shape shape;

    public Test1(Shape shape) {
        this.shape = shape;
    }

    public void doSomething() {
        shape.calculateArea();
        // ...
    }
}


// λ‚˜μœ 예, κΈ°λŠ₯을 μΆ”κ°€ν•˜κΈ° μœ„ν•΄μ„  ν•„λ“œμ™€ 쑰건문을 μΆ”κ°€ν•΄μ•Όν•˜λŠ” 변경이 ν•„μš”
class Test2 {
    private Circle circle = new Circle();
    private Rectangle rectangle = new Rectangle();

    public void doSomething(String shape) {
        if (shape.equals("circle")) {
            circle.calculateArea();
        } else if (shape.equals("rectangle")) {
            rectangle.calculateArea();
        }
        // ...
    }
}

μœ„ μ½”λ“œμ—μ„œ κΈ°λŠ₯을 μΆ”κ°€ν•˜κΈ° μœ„ν•΄μ„œλŠ” Shape μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 클래슀만 μΆ”κ°€ν•˜λ©΄ λœλ‹€.

LSP: λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙 (Liskov Substitution Principle)

  • κ°μ²΄λŠ” 정확성을 κΉ¨λœ¨λ¦¬μ§€ μ•ŠμœΌλ©΄μ„œ μƒμœ„ 클래슀의 객체λ₯Ό ν•˜μœ„ 클래슀둜 λŒ€μ²΄ κ°€λŠ₯ν•΄μ•Ό ν•œλ‹€.

  • λΆ€λͺ¨ 클래슀의 κ·œμ•…μ„ μžμ‹ ν΄λž˜μŠ€κ°€ λ‹€ μ§€μΌœμ•Ό ν•œλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.

class Parent {
    public int calculate(int a, int b) {
        return a + b;
    }
}

class Child extends Parent {
    @Override
    public int calculate(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("b cannot be zero");
        }
        return a / b;
    }
}

public class test {
    public static void main(String[] args) {
        Parent p = new Child();
        System.out.println(p.calculate(10, 0)); // IllegalArgumentException
    }
}

μœ„ μ½”λ“œμ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•˜μ§€ μ•Šμ§€λ§Œ 넓이λ₯Ό κ΅¬ν•˜λŠ”λ°μ— 논리적인 차이가 μžˆμ–΄ μ˜λ„ν•˜μ§€ μ•Šμ€ κ²°κ³Όκ°€ λ‚˜μ˜¬ 수 μžˆλ‹€.

ISP: μΈν„°νŽ˜μ΄μŠ€ 뢄리 원칙 (Interface segregation principle)

  • μ—¬λŸ¬ κΈ°λŠ₯을 ν¬ν•¨ν•œ λ²”μš© μΈν„°νŽ˜μ΄μŠ€ 보단 νŠΉμ • ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μœ„ν•œ μΈν„°νŽ˜μ΄μŠ€ μ—¬λŸ¬ 개λ₯Ό μƒμ„±ν•˜λŠ” 것이 μ’‹λ‹€.

  • μΈν„°νŽ˜μ΄μŠ€κ°€ λͺ…ν™•ν•΄μ§€λ©° λŒ€μ²΄ κ°€λŠ₯성이 λ†’μ•„μ§„λ‹€.

interface Printer {
    void print(Document document);
}

interface Scanner {
    void scan(Document document);
}

class AllInOnePrinter implements Printer, Scanner {
    public void print(Document document) {
        // 좜λ ₯ 둜직
    }

    public void scan(Document document) {
        // μŠ€μΊ” 둜직
    }
}

μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ—¬λŸ¬ 개둜 λΆ„λ¦¬ν•˜μ—¬ ν΄λž˜μŠ€μ— ν•„μš”ν•œ μΈν„°νŽ˜μ΄μŠ€λ§Œ κ΅¬ν˜„ν•˜λ„λ‘ ν•˜λ©΄, ν•„μš”ν•œ κΈ°λŠ₯만 μ‚¬μš©ν•  수 있고, λŒ€μ²΄ κ°€λŠ₯성도 λ†’μ•„μ§„λ‹€. λ˜ν•œ λΆˆν•„μš”ν•œ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜μ§€ μ•Šμ•„λ„ 되고, μ‚¬μš©ν•˜λŠ” ν΄λΌμ΄μ–ΈνŠΈμ—κ² λΆˆν•„μš”ν•œ λ©”μ„œλ“œλ₯Ό λ…ΈμΆœμ‹œν‚€μ§€ μ•ŠλŠ” μž₯점이 μžˆλ‹€.

DIP: 의쑴 μ—­μ „ 원칙 (Dependency inversion principle)

  • "좔상화에 μ˜μ‘΄ν•΄μ•Όν•˜κ³ , ꡬ체화에 μ˜μ‘΄ν•˜λ©΄ μ•ˆλœλ‹€."λ₯Ό λ”°λ₯΄λŠ” 원칙

  • κ΅¬ν˜„ ν΄λž˜μŠ€μ— μ˜μ‘΄ν•˜μ§€ μ•Šκ³ , μΈν„°νŽ˜μ΄μŠ€μ— μ˜μ‘΄ν•΄μ•Ό ν•œλ‹€.

  • κ΅¬ν˜„μ²΄μ— μ˜μ‘΄ν•˜κ²Œ 되면 변경이 μ–΄λ €μ›Œμ§€κ³ , ν…ŒμŠ€νŠΈλ„ μ–΄λ €μ›Œμ§„λ‹€.

interface PaymentProvider {
    void processPayment(int amount);
}

class KakaoPaymentProvider implements PaymentProvider {
    public void processPayment(int amount) {
        // 카카였페이 결제 둜직
    }
}

class OrderService {
    private final PaymentProvider paymentProvider;

    public OrderService(PaymentProvider paymentProvider) {
        this.paymentProvider = paymentProvider;
    }

    public void processOrder(Order order) {
        // 주문 처리 둜직
        paymentProvider.processPayment(order.getTotalAmount());
    }
}

class OrderServiceTest {
    void processOrder() {
        OrderService orderService = new OrderService(new KakaoPaymentProvider());
        orderService.processOrder(new Order());
    }
}

μœ„ μ½”λ“œλŠ” μΈν„°νŽ˜μ΄μŠ€μ˜ 쑴재둜 OrderService -> PaymentProvider <- KakaoPaymentProvider둜 의쑴 λ°©ν–₯이 μ—­μ „λ˜μ—ˆκΈ° λ•Œλ¬Έμ—, 변경이 μš©μ΄ν•΄μ§„ μ½”λ“œκ°€ λœλ‹€. ν•˜μ§€λ§Œ μΈν„°νŽ˜μ΄μŠ€κ°€ μ—†μ—ˆλ‹€λ©΄ OrderService -> KakaoPaymentProvider둜 μ˜μ‘΄ν•˜κ²Œ λ˜μ–΄ 변경이 μ–΄λ €μ›Œμ§€κ³ , ν…ŒμŠ€νŠΈλ„ μ–΄λ ΅κ²Œ λœλ‹€.

Last updated

Was this helpful?