좋은 객체지향설계의 5가지 원칙 : SOLID

  • SRP : 단일 책임 원칙(single responsibility principle)
  • OCP : 개방-폐쇄 원칙(Open/closed principle)
  • LSP : 리스코프 치환 원칙(Liskov substitution principle)
  • ISP : 인터페이스 분리 원칙(Interface segregation principle)
  • DIP : 의존관계 역전 원칙(Dependency inversion principle)

SRP : 단일 책임 원칙

어떤 클래스를 변경해야 하는 이유는 오직 하나 뿐이어야 한다.
로버트 C. 마틴(밥 아저씨)
  • 한 클래스(객체)는 하나의 책임만 가져야 한다.
  • 하나의 책임이라는것은 모호하지만, 중요한 기준은 변경이다.
    • 변경이 있을 때 파급 효과가 적어야 한다. (매우 중요)
class Calculator {

    public int calculate(String operator, int firstNumber, int secondNumber) {
        int answer = 0;

        if(operator.equals("+")){
            answer = firstNumber + secondNumber;
        }else if(operator.equals("-")){
            answer = firstNumber - secondNumber;
        }else if(operator.equals("*")){
            answer = firstNumber * secondNumber;
        }else if(operator.equals("/")){
            answer = firstNumber / secondNumber;
        }

        return answer;
    }
}

다음 코드의 문제점은 뭘까?

  1. 첫 번째로, Calculate의 책임감이 너무 무겁다. 혼자 "+"를 연산하는 메서드, "-"를 연산하는 메서드, "*"를 연산하는 메서드, "/"를 연산하는 메서드를 전부 짊어지고 있다.
  2. 두 번째로, 연산 기호가 바뀌었을 때나 각 연산 과정에서 변화가 생겼을 때 다른 연산 과정에도 영향을 끼칠 수 있다.
  3. "/"에서 예외처리가 되지 않았다.

=> 해결 방안

  1. Calculate에는 사칙연산을 실행하는 메서드만 넣는다.
  2. 상세한 내용은 각 클래스로 구현하되, calculate 클래스에서는 각 클래스를 불러온다.
  3. 예외처리를 해준다.
class Calculator {
    private int firstNumber;
    private int secondNumber;
    public Calculator(){
        this.firstNumber = 0;
        this.secondNumber = 0;
    }

    public Calculator(int firstNumber, int secondNumber) {
        this.firstNumber = firstNumber;
        this.secondNumber = secondNumber;
    }

    public int addOperation() {
        AddOperation addOperation = new AddOperation(firstNumber,secondNumber);
        return addOperation.operate();
    }
    public int subtractOperation(){
        SubstractOperation substractOperation = new SubstractOperation(firstNumber, secondNumber);
        return substractOperation.operate();
    }

    public int multiplyOperation(){
        MultiplyOperation multiplyOperation = new MultiplyOperation(firstNumber,secondNumber);
        return multiplyOperation.operate();
    }
    public double divideOperation() {
        DivideOperation divideOperation = new DivideOperation(firstNumber, secondNumber);
        return divideOperation.operate();
    }

    public void setFirstNumber(int firstNumber) {
        this.firstNumber = firstNumber;
    }

    public void setSecondNumber(int secondNumber) {
        this.secondNumber = secondNumber;
    }
}

class DivideOperation{
    private int firstNumber;
    private int secondNumber;

    public DivideOperation(int firstNumber, int secondNumber) {
        this.firstNumber = firstNumber;
        this.secondNumber = secondNumber;
    }

    public void setFirstNumber(int firstNumber) {
        this.firstNumber = firstNumber;
    }

    public void setSecondNumber(int secondNumber) {
        this.secondNumber = secondNumber;
    }

    public double operate(){
        try{
            return firstNumber/secondNumber;
        } catch(ArithmeticException e){
            System.out.println("0으로 나눌수 없습니다. 다시 계산해주세요");
            exit(0);
        }
        return firstNumber/secondNumber;
    }
}

Calculator와 나눗셈 영역만 업로드했다. 나눗셈은 try-catch로 0으로 나눌 때를 대비해 ArithmeticException을 걸렀고,

지금은 아니지만 혹시나 계산기 내의 메서드가 비밀이라고 할 때를 대비해 인자들을 private로 감쌌다.

 

의외로 try-catch문으로 감싸는걸 까먹어서 오래 걸렸다.

+ Recent posts