리팩토링 17. 변수 캡슐화하기

    들어가기 전

    이 글은 인프런 백기선님의 강의를 복습하며 작성한 글입니다. 


    리팩토링 17. 변수 캡슐화하기 (Encapsulate Variable)

    • 메서드는 점진적으로 새로운 메서드로 변경할 수 있다. 반면 데이터는 한번에 모두 변경해야한다.
    • 데이터를 변경하는 작업은 메서드를 변경하는 작업보다 어렵다.
      • 따라서 메서드를 통해서 데이터에 접근하도록 하면, 수정 작업이 필요할 때 메서드 수정을 통해서 점진적으로 처리할 수 있다. 
    • 데이터 구조를 변경하는 작업을 그보다는 조금 더 수월한 메서드 구조 변경 작업으로 대체할 수 있다. 
    • 데이터가 사용되는 범위가 클수록 캡슐화를 하는 것이 더 중요해진다. 
      • 메서드를 사용해서 값을 변경하면 부가기능(검증 로직, 후속 작업)을 캡슐화 할 수 있음. 
      • 변수 이름에 직접 접근하는 경우, 전체 범위를 모두 수정해야하는데 메서드로 캡슐화 하면 점진적으로 수정할 수 있음. 
    • 불변 데이터의 경우에는 이런 리팩토링을 적용할 필요가 없다. 

    메서드는 점진적으로 변경 가능 / 변수는 한꺼번에 변경해야 함. 

    일반적으로 변수를 변경하는 것보다 메서드를 변경하는 것이 더 쉽다. 변수를 변경할 때는 이 변수를 사용하는 모든 곳을 함께 수정해줘야하기 때문이다. 반면 메서드를 변경할 때는 기존 메서드를 그대로 둔 상태로 새로운 메서드를 만들고, 코드의 일부분이 새로운 메서드를 사용하게끔 점진적으로 고쳐나갈 수 있기 때문이다. 그렇기 때문에 만약에 변수에 직접 접근해서 사용하는 코드들이 있다면 가급적이면 메서드로 감싸주는 것이 좋다.


    데이터가 사용되는 범위가 클수록 캡슐화를 하는 것이 더 중요해진다.

    변수의 범위(로컬 → 클래스 → 전역)가 커지면 커질수록 변수의 변경에 대처하기가 어려워진다. 그만큼 변수가 사용되는 범위가 넓어지기 때문이다. 따라서 가급적이면 변수를 메서드로 감싼 후, 메서드를 통해서 변수에 접근 / 수정하는 형태가 되도록 하는 것이 좋다. 이렇게 하면 변수를 수정하더라도 변경점이 메서드로 추상회 되어 있기 때문에 변경지점이 적어진다. 

    또한 메서드로 변수를 캡슐화한다면 부가기능(Validation, 후처리) 로직을 좀 더 손쉽게 캡슐화를 할 수 있다는 장점 역시 존재한다. 


    불변 데이터의 경우에는 이런 리팩토링을 적용할 필요가 없다. 

    불변 데이터는 데이터가 변경되지 않기 때문에 부가기능을 추가할 필요가 없다. 오로지 값에 접근해서 데이터를 가져가는 기능만 있기 때문에 멱등하다. 따라서 불변 데이터라면 메서드로 캡슐화를 하지 않아도 괜찮을 수 있다. 

    그럼에도 불구하고 불변 데이터의 '이름'이 바뀐다면, 변경 지점이 데이터의 Scope만큼 퍼질 수 있다. 따라서 개인적으로는 불변 변수라도 메서드 캡슐화로 접근하는 것이 좋을 것으로 판단된다. 


    Encapsulate Variable (Before)

    아래 코드는 리팩토링을 수행하기 전의 코드다. 문제점을 살펴보자.

    • 전역 변수에 직접 접근 / 수정이 가능하다.

    이 상태는 다음 문제를 야기할 수 있다. 

    • targetTemperature에 터무니 없는 값이 들어올 수 있다. (-1117503 같은 값) → Validation의 필요성
    • 전역에서 사용할 수 있기 때문에 변경 지점이 한없이 넓어진다. → 변수 이름 수정 시, 변경해야 할 부분 많아짐. 

    따라서 해당 부분을 해결하기 위해서 '변수'를 메서드 캡슐화를 통해서 한번 감싸줘야한다. 메서드 캡슐화를 하게 될 경우 다음과 같은 장점이 있다. 

    • 메서드를 통해서 변수에 접근 및 수정한다. 이 때 메서드 내부에서 전/후처리 부가기능을 캡슐화 할 수 있다.
    • 메서드로 변수가 추상화 되기 때문에 변수 이름의 변경이 전체로 퍼지지 않는다. 

    여기서는 메서드 캡슐화를 통해서 위 문제를 해결해보고자 한다. 

    public class Home {
    
        public static void main(String[] args) {
            System.out.println(Thermostats.targetTemperature);
            // 전역 변수에 직접 접근 → 메서드로 변수 캡슐화 필요함.
            Thermostats.targetTemperature = 68;
            Thermostats.readInFahrenheit = false;
        }
    }
    
    public class Thermostats {
    	// 전역 변수 : 직접 접근 / 수정 가능함. 
        public static Integer targetTemperature = 70;
        public static Boolean heating = true;
        public static Boolean cooling = false;
        public static Boolean readInFahrenheit = true;
    
    }

     


    Encapsulate Variable (After)

    리팩토링 전에는 전역 변수에 직접 접근 / 수정이 가능했고, 이것은 여러 문제점을 야기했다. 이 부분을 해결하기 위해서 변수 접근 / 수정을 Getter / Setter 메서드를 통해서 캡슐화 했다. 

    public class Home {
    
        public static void main(String[] args) {
            System.out.println(Thermostats.getTargetTemperature());
            Thermostats.setTargetTemperature(68);
            Thermostats.setReadInFahrenheit(false);
        }
    }
    
    
    // 메서드를 이용한 변수 캡슐화
    public class Thermostats {
    
        private static Integer targetTemperature = 70;
        private static Boolean heating = true;
        private static Boolean cooling = false;
        private static Boolean readInFahrenheit = true;
    
        // 메서드로 캡슐화
        public static Integer getTargetTemperature() {
            return targetTemperature;
        }
    
        public static void setTargetTemperature(Integer targetTemperature) {
            // Validation 추가 가능
            Thermostats.targetTemperature = targetTemperature;
        }
    
        public static Boolean getHeating() {
            return heating;
        }
    
        public static void setHeating(Boolean heating) {
            // Validation 추가 가능
            Thermostats.heating = heating;
        }
    
        public static Boolean getCooling() {
            return cooling;
        }
    
        public static void setCooling(Boolean cooling) {
            // Validation 추가 가능
            Thermostats.cooling = cooling;
        }
    
        public static Boolean getReadInFahrenheit() {
            return readInFahrenheit;
        }
    
        public static void setReadInFahrenheit(Boolean readInFahrenheit) {
            // Validation 추가 가능
            Thermostats.readInFahrenheit = readInFahrenheit;
        }
    }

    정리하기

    • 메서드 캡슐화를 통해서 변수에 직접 접근 / 수정하는 것을 막아야 한다.
    • 메서드 캡슐화를 이용하면 변경 지점을 줄일 수 있고, 점진적 변경이 가능하다는 장점이 있다. 
    • 전역 변수는 상수인 경우에만 사용한다.
    • 전역 변수로 사용해야 한다면 final 키워드를 이용해서 불변으로 선언해야 한다. 이 경우라면 메서드 캡슐화를 하지 않아도 괜찮을 수 있다. 
    • 전역 변수 뿐만 아니라 클래스 필드도 메서드를 이용해서 접근하도록 한다.

    댓글

    Designed by JB FACTORY