Spring_부캠

[Java] SSR & Refactoring

FS29 2025. 7. 15. 20:45

 

SRP

단일책임의 원칙.

하나의 클래스는 오직 한 가지 일만 맡아야 한다는 원칙.

 

이점으로는 유지보수 용이(버그가 나면 해당 클래스의 한 영역만 살펴보면 됨), 재사용성 증가(연산이 명확히 분리되어 있으니 다른 프로젝트에서 덧셈기만 따로 빼서 쓸 수 있음)

// SRP위반예제
// 하나의 클래스가 “계산”도 하고 “결과 출력”도 담당하고 있다면 SRP를 위반한 것!
public class Calculator {
    // 덧셈 기능
    public double add(double a, double b) {
        return a + b;
    }

    // 뺄셈 기능
    public double subtract(double a, double b) {
        return a - b;
    }

    // 결과를 화면에 출력
    public void printResult(double result) {
        System.out.println("계산 결과: " + result);
    }
}

 

위 코드의 문제점

  • Calculator클래스 계산(add, subtract)과 출력이라는 서로 다른 두 가지 책임을 가지고 있음.
  • 따라서 기능이 늘어날수록 유지보수가 어렵고 테스트하기도 번거로움이 있음

SRP적용 후

  • 계산만 전담하는 Calculator클래스
public class Calculator {
    public double add(double a, double b) {
        return a + b;
    }

    public double subtract(double a, double b) {
        return a - b;
    }
}

 

 

  • 출력만 전담하는 ResultPrinter클래스
public class ResultPrinter {
    public void print(double result) {
        System.out.println("계산 결과: " + result);
    }
}

 

 

  • 두 클래스를 조합해서 사용하는 App클래
public class App {
    public static void main(String[] args) {
        Calculator calc = new Calculator();            // 계산 책임
        ResultPrinter printer = new ResultPrinter();   // 출력 책임

        double sum = calc.add(10, 5);
        printer.print(sum);

        double diff = calc.subtract(10, 5);
        printer.print(diff);
    }
}

 

포함 관계(Composition) & 전략 패턴(Strategy Pattern)

 

1. 포함 관계(Composition)이란?

A 클래스가 B 객체를 ‘가지고 있다(has-a)라는 설계방식.

 

비유

 

  • 자동차(Car) 는 엔진(Engine) 을 포함
  • 회사(Company) 는 직원(Employee) 들을 포함

 

 

왜 쓰는지

  • 여러기능을 모아놓기 보다 필요한 객체를 내부에 들고 있어서 책임을 분리
  • 객체 간 결합도 낮춰 유연성 높음
// 포함 관계 예시: Car has-a Engine
class Engine {
    void start() { System.out.println("부릉부릉"); }
}

class Car {
    private final Engine engine;        // Car는 Engine을 포함(has-a)

    public Car() {
        this.engine = new Engine();     // 생성자에서 Engine 초기화
    }

    public void drive() {
        engine.start();                 // 포함된 Engine 객체를 사용
        System.out.println("달린다!");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.drive();  // → 부릉부릉  달린다!
    }
}

Car 안에는 Engine이 필드로 들어가 있으니 Car는 언제든 engine.start()를 호출할 수 있음

 

 

 

2. 전략 패턴(Strategy Pattern)이란?

알고리즘(또는 기능)을 캡슐화해서, 실행 시점에 ‘전략(Strategy)’을 교체할 수 있게 만든 패턴.

 

  • 알고리즘(또는 기능)을 캡슐화
  • 필요할 때마다 전략(strategy) 을 교체할 수 있도록

 

왜 쓰는지

1) 조건문(if/else) 폭탄 방지

// 조건문만 늘어나다 보면 유지보수가 지옥…
if(symbol == '+') return a + b;
else if(symbol == '-') return a - b;
else if(symbol == '*') return a * b;
// …

 

2) 새 알고리즘 추가 시

 

  • 기존 코드를 한 줄도 손대지 않고
  • 새로운 클래스만 만들어서 주입(injection)하면 끝

 

 

 

 

생성자 활용

생성자(Constructor)란 무엇인가?

 

  • 특별한 메서드로, 클래스 이름과 동일하며 반환 타입이 없음
  • new 클래스명(...) 할 때 항상 한 번 호출되어 객체 초기

 

public class Person {
    private String name;
    private int age;

    // 기본 생성자: 파라미터 없고, JVM이 자동 생성해주기도 함
    public Person() { }

    // 파라미터 생성자: 호출 시 name, age를 반드시 받아야 함
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

객체가 만들어질 때(인스턴스화) 필요한 정보를 반드시 한 번에 채워 넣는 특별한 메서드.

이점으로는 불변성 보장(final 필드를 생성자에서 초기화하면 이후 절대 null이 될 수 없음), 테스트 편의(생정자 파라미터를 바꿔가며 다양한 환경을 쉽게 주입 가능)

 

public class Calculator {
    private final AddOperator add;
    private final SubtractOperator sub;

    // 생성자에서 딱 한 번 초기화
    public Calculator() {
        this.add = new AddOperator();
        this.sub = new SubtractOperator();
    }

    public double add(double a, double b) {
        return add.apply(a, b);
    }
    public double subtract(double a, double b) {
        return sub.apply(a, b);
    }
}

 

 

 

OCP

 

개방폐쇄의 원칙.

확장에는 열려 있어야(Open for extension), 수정에는 닫혀 있어야(Closed for modification) 함.

=> 기존 코드는 바꾸지 않고 새로운 기능만 깔끔하게 추가할 수 있어야 한다는 원칙.

//새 연산(예: PowerOperator)을 추가할 땐 → 기존 코드 한 줄도 고치지 않고
//1)PowerOperator implements Operator 클래스 생성
//2)new PowerOperator()를 ArithmeticCalculator 생성자 인자에 추가
public class PowerOperator implements Operator {
    public char symbol() { return '^'; }
    public double apply(double a, double b) { return Math.pow(a, b); }
}

// 기존 ArithmeticCalculator 코드는 전혀 변경 필요 없음!
List<Operator> ops = List.of(
    new AddOperator(), new SubtractOperator(),
    new MultiplyOperator(), new DivideOperator(),
    new PowerOperator()          // 추가
);
ArithmeticCalculator calc = new ArithmeticCalculator(ops);

 

 

'Spring_부캠' 카테고리의 다른 글

[Java] 제발 기억해  (0) 2025.07.18
[Java] OOP  (0) 2025.07.16
[JAVA] MORE.1  (2) 2025.07.08
[JAVA] Level.1_Calculator  (0) 2025.07.07
[JAVA] Optional, Collection, Generic  (1) 2025.06.30