(내일배움캠프)Java - 3주차 숙제

Thomas·2023년 5월 30일
0
post-thumbnail

Step1

더하기, 빼기, 나누기, 곱하기 연산을 수행할 수 있는 Calculator 클래스

Calculator Class

public double calculate(String operator,int firstNumber, int secondNumber){
        double ret = 0.0;

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

테스트

public class Main {
    public static void main(String[] args) {
        Calculator cal = new Calculator();

        int firstNum = 2;
        int secondNum = 2;
        System.out.println(firstNum + " + " + secondNum + " = "  + cal.calculate("+",firstNum,secondNum));
        System.out.println(firstNum + " - " + secondNum + " = "  + cal.calculate("-",firstNum,secondNum));
        System.out.println(firstNum + " * " + secondNum + " = "  +cal.calculate("*",firstNum,secondNum));
        System.out.println(firstNum + " / " + secondNum + " = "  +cal.calculate("/",firstNum,secondNum));
    }
}

결과


Step2

-> %연산자 추가라 가볍게 패스


Step3

AddOperation(더하기), SubstractOperation(빼기), MultiplyOperation(곱하기), DivideOperation(나누기) 연산 클래스를을 만든 후 클래스간의 관계를 고려하여 Calculator 클래스와 관계를 맺습니다.

  • 관계를 맺은 후 필요하다면 Calculator 클래스의 내부코드를 변경합니다.

AddOperation Class

public class AddOperation {
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber + secondNumber;
    }
}

SubstractOperation Class

public class SubstractOperation {
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber - secondNumber;
    }
}

MultiplyOperation Class

public class MultiplyOperation {
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber * secondNumber;
    }
}

DivideOperation Class

public class DivideOperation {
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber / secondNumber;
    }
}

Calculator Class

public class Calculator {
    private final AddOperation addOperation;
    private final SubstractOperation substractOperation;
    private final MultiplyOperation multiplyOperation;
    private final DivideOperation divideOperation;

    public Calculator() {
        this.addOperation = new AddOperation();
        this.substractOperation = new SubstractOperation();
        this.multiplyOperation = new MultiplyOperation();
        this.divideOperation = new DivideOperation();
    }

    public double add(int firstNum, int secondNum) {
        return addOperation.operate(firstNum,secondNum);
    }

    public double substract(int firstNum, int secondNum) {
        return substractOperation.operate(firstNum,secondNum);
    }

    public double multiply(int firstNum, int secondNum) {
        return multiplyOperation.operate(firstNum,secondNum);
    }

    public double divide(int firstNum, int secondNum) {
        if(secondNum == 0) {
            throw new ArithmeticException("0을 나눌수 없습니다");
        }
        return divideOperation.operate(firstNum,secondNum);
    }
}

Main

public class Main {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();

        System.out.println(calculator.add(2,2));
        System.out.println(calculator.subtract(2,2));
        System.out.println(calculator.multiply(2,2));
        System.out.println(calculator.divide(2,2));
    }
}

Step 1 와 비교하여 어떠한 점이 개선 되었는지 스스로 생각해 봅니다.

자바의 코드는 SOLID원칙을 따라야 좋은 코드이다
Step 2에서 한 작업은 SOLID의 S인 SRP(Single Responsibility) 단일책임을 지킨 케이스이다.

좀더 설명 하자면

SRP

  • 한 클래스는 하나의 책임만 가져야한다
  • 하나의 책임이라는 것은 모호하다
    클수도 있고, 작을 수도 있다
    문맥과 상황에 따라 다르다
  • 중요한 기준은 변경이다. 변경이 있을 떄 파급효과가 적으면 단일 책임 원칙을 잘 따른것

Step1에서는 Calculator Class 하나에 calculate 메소드가 존재한다

그러면 Calulator Class에선 하나의 책임만 있는가?
아니다 +,-,*,/ 4가지 책임이 있다... 그런즉 단일책임이 아닌셈이다

그러면 Step 2를 보다
Calulator Class에선 각 operation을 정해주는 하나의 책임과
add,sub,mul,div Class에서는 각 operation을 수행해주는 하나의 책임이 있다,
즉 SRP를 잘 따른셈이다.


Step4

AddOperation(더하기), SubstractOperation(빼기), MultiplyOperation(곱하기), DivideOperation(나누기) 연산 클래스들을 AbstractOperation(추상 클래스)를 사용하여 추상화하고 Calculator 클래스의 내부 코드를 변경합니다.

UML 보시기 전에 아래의 관계는 모두 포함관계라고 보시면 됩니다!!

추상 클래스를 쓴다. 즉 미완성 설계도이라 완성된 제품을 만들 수 없듯이 추상 클래스로 인스턴스를 생성할 수 없다.
그래서 추상 클래스는 상속을 통해서 자손클래스에 의해서만 완성 시킬수 있다.
-> 자손인 AddOperation,SubstractOperation,MultiplyOperation,DivideOperation Class에서 완성을 시켜줘야 한다!

AddOperation Class

public class AddOperation extends AbstractOperation {
    @Override
    double operate(int firstNumber, int secondNumber) {
        return firstNumber + secondNumber;
    }
}

SubstractOperation Class

public class SubstractOperation extends AbstractOperation{
    @Override
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber - secondNumber;
    }
}

MultiplyOperation Class

public class MultiplyOperation extends AbstractOperation{
    @Override
    public double operate(int firstNumber, int secondNumber) {
        return firstNumber * secondNumber;
    }
}

DivideOperation Class

public class DivideOperation extends AbstractOperation{
	@Override
	public double operate(int firstNumber, int secondNumber) {
        return firstNumber / secondNumber;
    }
}

AbstractOperation

abstract class AbstractOperation {

    abstract double operate(int firstNumber, int secondNumber);
}

Calculator Class

public class Calculator {
    private AbstractOperation operation;

    public Calculator(AbstractOperation operation){
        this.operation = operation;
    }

    public double calculate(int firstNum, int secondNum) {
        return operation.operate(firstNum,secondNum);
    }
}

Main

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("시용할 연산자를 선택하세요 (+,-,*,/)");
        String operator;
        operator= sc.nextLine();

        AbstractOperation operation = null;

        while(!"+".equals(operator) && !"-".equals(operator) && !"*".equals(operator) && !"/".equals(operator)) {
            System.out.println("잘못된 연산자를 사용하였습니다");
            System.out.println("시용할 연산자를 선택하세요 (+,-,*,/)");
            operator = sc.nextLine();
        }

        if("+".equals(operator)) {
            operation = new AddOperation();
        }
        else if("-".equals(operator)){
            operation = new SubstractOperation();
        }
        else if("*".equals(operator)){
            operation = new MultiplyOperation();
        }
        else if("/".equals(operator)){
            operation = new DivideOperation();
        }

        Calculator calculator = new Calculator(operation);

        System.out.println("첫 번째 숫자를 입력하세요:");
        int firstNum = sc.nextInt();
        sc.nextLine();

        System.out.println("두 번째 숫자를 입력하세요:");
        int secondNum = sc.nextInt();

        System.out.println(firstNum + " " + operator + " " + secondNum + "= " + calculator.calculate(firstNum,secondNum));
    }
}

결과값

Step 3 와 비교해서 어떠한 점이 개선 되었는지 스스로 생각해 보기

DIP

  1. DIP(Dependency Inversion)원칙이 추가가 되었다!
    DIP 원칙이란 객체에서 어떤 클래스를 참조해서 사용해야하는 상황이 생긴다면, 그 클래스를 직접 참조하는 것이 아니라 그 대상의 상위 요소(추상클래스 또는 인터페이스)
    객체들이 서로 정보를 주고 받을 떄는 의존 관계가 형성 되는데, 이 때 객체들은 나름대로의 원칙을 갖고 정보를 주고 받아야 하는 약속이 있다. 여기서 나름대로의 원칙이란 추상성이 낮은 클래스보다 추상성이 높은 클래스와 통신. 즉, DIP 원칙이다

자바에서 인터페이스에 대해 학습할 떄 매개변수로 객체를 받을 때 구체 클래스 타입으로 받는게 아니라, 다형성을 이용해 인터페이스 타입으로 통신하는 것이 좋다.
대표적으로 컬렉션 프레임워크에서 ArrayList 자료형을 인스턴스화 할 때 변수 타입으로 ArrayList 구체 클래스 타입으로 선언하는 것이 아닌 List 같은 인터페이스 타입으로 선언.
이 또한 DIP 원칙을 따른것이다!!

결합도(coupling)

  1. 클래스간의 결합도
    결합도란?
    다른 것과 얼만 ㅏ강력하게 연결되어 있는지, 또한 얼머나 의존적인지 나타내는 정도. 즉, 자식 클래스가 부모 클래스를 의존을 얼마나 하는가

높은 결합도의 문제점

  • 연관된 다른 클래스가 변경되면 더불어 변경해야한다
  • 수정하려는 클래스를 이해라기 위해 연관된 다른 클래스를 함꼐 이해해야한다
  • 재사용하기 힘들다

위에 문제점을 보아 step4 코드는 낮은 결합도를 가지고 있다

그래서 위에 숙제는 추상클래스를 통해 나머지 연산자 operation 클래스안에서 operate 메소드를 override해서 완성을 시켜서 사용을 한다!

Calculator의 calculate 메서드의 매개변수가 변경

더이상 연산자를 매개변수의 통해 받을 필요가 없습니다!!
왜냐하면 해당 연산자로 opertaion으로 받기떄문에 그 operation은 해당 연산자로 밖에 쓰이지 못한다!

profile
Backend Programmer

0개의 댓글