ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 설계 품질 TradeOff [오브젝트 chpt 4]
    ProgrammingTheory/OOP 2023. 4. 7. 22:46

    - 이 글은  책 오브젝트 리뷰를 위한 메모 글이며, 공부 목적을 위한 노트 입니다.

     

    객체지향 설계 두 가지 방식 

     

    상태 중심 : 구현이 불안정하기 때문에 객체의 상태가 인터페이스에 스며드는 변경에 취약한 코드가 생길 수 있다.

    예시 )

    필요한 기능을 만들기 위하여 데이터를 우선적으로 생각하여 클라스를 만든후 접근 제어자를 넣어준후

    중앙에서 통재하는 클라스에서 모든 객체의 상태를 호출하여 원하는 결과를 만드는 방식.

    책에서는 데이터를 가지는 구현채들이 get ,set 이외의 로직이 없다.

    작년 겨울에 짰던 코드: MVC 패턴을 생각 했지만 내부의 BL 이 없다.

     

    public class Player {
        private Exception exception;
        private List<Integer> playerNumbers;
    
        public Player() {
            this.playerNumbers = new ArrayList<>();
            this.exception = new Exception();
        }
    
        public List<Integer> getPlayerNumbers() {
            return playerNumbers;
        }
        
    
        public void setPlayerNumbers(String inputNumber) {
            List<Integer> inputNumbers = Arrays.stream(inputNumber.split("", inputNumber.length()))
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
            this.playerNumbers = inputNumbers
        }
    }

    GameController class 의 playGame() ,

    1. swingBat 함수를 player 에 넣는게 더 좋아 보인다.
    2. Controller 는 간단하게 메시지만 전달하게 바꿔주고 model 에 BL 을 넣는게 더 책임 중심인것 같다.
    private void playGame() {
            Computer computer = new Computer();
            int gameRound = Constant.GAME_INIT;
            while (gameRound != Constant.RESULT_FULL_STRIKE) {
                Player player = inputController.readyPlayer();
    	           swingBat(computer.getComputerNumbers(), player.getPlayerNumbers());
                gameRound = setResultGame();
                outputView.getResultGameMessage(gameRound, this.getBall(), this.getStrike());
            }
            checkRestartGame();
        }

     

     

    책임 중심:

    객체의 행위를 최우선으로 생각하는 설계 방식

    두 가지설계 방식의 장단점을 비교하기 위하여 고려할 3 가지 기준 사항

    1. 캡슐화
    2. 응집도
    3. 결합도

    캡슐화

    상태와 행동을 하나의 객체로 모으는 추상화의 한종류로 설계의 1원칙이다.

    Point : 변경될 수 있는 가능성을 가진 모든 것은 반드시 캡슐화 해야한다.”

    -객체의 내부 구현을 외부로 감추어 객체간 결합도 낮춘다 : 변경사항의 유연하게 대응 가능하다

    • 구현 : 변경될 가능성이 높은 부분
    • 인터페이스 : 구현보다 상대적으로 안정적인 부분 , 외부에서는 인터페이스에만 의존하도록 하자.
    • (SOLID : DIP)

    접근자,수정자만 있는 구현방식은 코드의 중복을 야기할 수 있다.

    -캡슐화가 잘되어 있는지 확인하는 법 :

    1. 내부의 데이터를 자기 자신을 스스로 처리를 했는가?
    2. 내부의 구현이 외부의 구현의 변경을 야기하는 파급효과가 있는가?

    응집도

    모듈에 포합된 내부 요소들이 연관돼 있는 정도.

    모듈 내의 요소들이 하나의 목적을 위해 긴밀하게 연관되어 있으면 응집도가 높다라고 표현이 가능하다.

    객체 지향 관점 에서는 객체 또는 클래스에 얼마나 관련 높은 책임들을 할당했는지를 나타낸다.

    하나의 모듈 전체가 변경되는것을 높은 응집도라고 본다.

     

    로버트 마틴의 SOLID 에서 SRP 와 관련하여

    클라스는 단 한가지의 변경 이유만 가져야 한다라는 내용이있다.

     

    R : 책임이란 변경의 이유라는 의미로 , 서로 다른 이유로 변경되는 코드가 하나의 모듈에 있으면 안되며, 코드의 변경사항의 파급력이 얼만큼 큰지가 좋은 기준이 된다. 변경의 맞추어 엉뚱한 모듈의 코드를 수정해야한다면 응집도가 낮은 것을 인지하자.

     

    결합도

    의존성을 나타낸다.

    하나의 모듈이 다른 모듈의 모든 세부 정보를 안다라고 하면 높은 결합도를 가지는 것으로 볼 수 있다. 필수적인 정보만 알게 설계를 하자.

    변경 사항이 주어졌을때 파급 효과를 생각해 보는게 좋은 기준이 된다.

    정리 :

    1. 캡슐화를 높이는 것을 생각하자 : 기본
    2. 변경 사항이 매우 적다면 1번으로 어느정도 충분
    3. 인터페이스를 이용을 적극적으로 하여 높은 응집도 낮은 결합도를 만들자. (SOLID , OCP ,ISP,DIP)

     

    데이터 중심 코드를 다시 보자

     

    public class Player {
        private Exception exception;
        private List<Integer> playerNumbers;
    
        public Player() {
            this.playerNumbers = new ArrayList<>();
            this.exception = new Exception();
        }
    
        public List<Integer> getPlayerNumbers() {
            return playerNumbers;
        } 
    
        public void setPlayerNumbers(String inputNumber) {
            List<Integer> inputNumbers = Arrays.stream(inputNumber.split("", inputNumber.length()))
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
            this.playerNumbers = inputNumbers
        }
    }

     

     

    get 과 set 을 사용하여 캡슐화를 잘 한 것 처럼 보이지만, 외부 퍼블릭 인터페이스에 playerNumbers 라는 인스턴스 변수가 존재한다라는 것 을 대놓고 알려 주는 것이다.

     

    협력을 전혀 고려 하지 않았기 때문에 과도한 접근자 및 수정자를 가지게 된다.

Designed by Tistory.