ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 이펙티브 자바 Item 16 - public 클래스에서는 public필드가 아닌 접근자 메서드를 사용하라
    언어/Effective Java 2024. 5. 30. 09:52

     

    1. 접근자 메서드를 활용한 데이터 캡슐화 

    • 대표적인 클래스 작성 실수: 인스턴스 필드만을 모아놓은 퇴보한 클래스 
    • 인스턴스 필드만을 모아놓은 클래스는 데이터 직접 접근할 수 있으나 캡슐화의 이점을 제공하지 못한다.
    public class Point {
        public double x;
        public double y;
    }

     

    • 캡슐화가 전혀 안되기 때문에 아래와 같은 단점을 수반한다. 
      • API를 수정하지 않고는 내부 표현을 바꿀 수 없다
      • 불변식을 보장하지 못한다.
      • 외부에서 필드에 접근할 때 부수작업을 수행할 수 없다.

    *API 수정부분 

    Point.getValue() 같은 메서드를 호출해서 x,y를 얻는다고 했을 때 내부 구현 로직이 캡슐화되어 있기 때문에 얼마든지 바꿀 수 있음 

    Point.x로 접근했을 때, 만약 x의 이름이 xy로 바뀐다면, Point.x를 사용하는 모든 클래스를 수정해줘야할 것임

     


    2. 클래스 캡슐화 

     

    class Point {
    
        private double x;
        private double y;
    
        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }
    
        public double getX() { return x; }
        public double getY() { return y; }
    
        public void setX(double x) { this.x = x; }
        public void setY(double y) { this.y = y; }
    
    }
    • getter/setter 메서드를 통해 언제든지 내부 표현을 바꿀 수 있다.
    • 불변식이 보장된다.
      • 클라이언트는 메서드를 통해서만 필드에 접근 가능하다.
    • 외부에서 필드에 접근할 때 부수 작업을 수행 시킬 수 있다.
      • getter/setter 메서드에 얼마든지 추가 가능하다.

    객체지향의 장점을 이끌어내려면, 아무리 단순한 데이터(필드)라도 이처럼 캡슐화를 진행하는 것이 좋다.

     

     2.1 private 중첩 클래스

    • 하지만 pakage-private 혹은 private 중첩 클래스라면 데이터 필드를 노출한다 해도 문제가 없다
    public class TopPoint {
    
        private static class Point {
            public double x;
            public double y;
        }
    
        public Point getPoint() {
            Point point = new Point();  // TopPoint 외부에선
            point.x = 3.5;              // Point 클래스 내부 조작이
            point.y = 4.5;              // 불가능 하다.
            return point;
        }
    
    }
    • 위와 같이 private 클래스를 중첩시키면 TopPoint 클래스에서는 얼마든지 Point클래스의 필드를 조작할 수 있지마느 외부 클래스에서는 Point 클래스의 필드에 직접 접근 할 수 없다.

     

    • package-private 클래스 역시 해당 클래스가 포함되는 패키지 내에서만 조작이 가능하고 패키지 외부에서는 접근이 불가능 하므로, 처음 제시된 3가지 문제점을 모두 메꿀 수 있다.

     

    • point.x로 접근해서 사용하면 훨씬 사용이 편리하긴 하다. 이런 장점을 살리면서 캡슐화의 이점도 가져간다.

    *public class에서 public 필드를 만들면 공개 API라서 클라이언트가 전 세계이다. 이는 수정이 매우 어렵다.

    하지만, package-private나 private 중첩 클래스에 public은 수정 범위가 패키지 내부나 클래스 내부이므로, 비교적 수정이 용이하다.

     

     

    public을 노출하되, 불편 필드로 만들기 

    public class Time {
        private static final int HOURS_PER_DAY = 24;
        private static final int MINUTES_PER_HOUR = 60;
        
        public final int hour;
        public final int minute;
    
        public Time(final int hour, final int minute) {
            this.hour = hour;
            this.minute = minute;
        }   
    }

     

    • public 클래스 필드가 불변이라면 직접 노출할 때의 단점이 조금 줄어든다.
    • 다만 API를 변경하지 않고는 표현 방식을 바꿀 수 없고, 필드를 읽을 때 부수적인 작업을 수행할 수 없다는 단점이 변하지 않는다.

     

Designed by Tistory.