ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 불변객체
    카테고리 없음 2024. 7. 16. 22:32

    불변객체란?

    • 불변객체란 상태값을 수정할 수 없는 객체를 의미한다.
    • 즉, 객체를 처음 생성(초기화) 후에는 객체가 가지는 상태를 변경할 수 없는 것을 의미한다.

    불변객체를 만드는 방법

    1) 캡슐화를 통해 내부 변수 접근 불가

    public class Immutable {
        String address = "대한민국 서울시";
        String gender = "female";
        String identityNumber = "9706192034623";
    
        public String getAddress() {
            return address;
        }
    
        public String getGender() {
            return gender;
        }
    
        public String getIdentityNumber() {
            return identityNumber;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public void setIdentityNumber(String identityNumber) {
            this.identityNumber = identityNumber;
        }
    }

    다음은 개인 정보를 가진 class 이다. 주소, 성별, 주민등록번호를 가지고 있으며 외부에서는 getter(), setter() 를 통해 데이터를 조회, 수정 할 수 있다. 여기서 문제는 setter()를 통해 변경하면 안되는 값이 변경 될 가능성이 있다는 것이다.

     

    public class Immutable {
        private String address = "대한민국 서울시";
        private String gender = "female";
        private String identityNumber = "9706192034623";
    
        public String getAddress() {
            return address;
        }
    
        public String getGender() {
            return gender;
        }
    
        public String getIdentityNumber() {
            return identityNumber;
        }
    }

    1. 내부 인스턴스 변수는 getter() 메소드를 통해서만 접근 가능하도록 private으로 변경하였다.

    2. setter() 메소드를 삭제하여 외부에서 값을 변경 할 수 없도록 하였다.

     

    캡슐화를 통해 공개된 인터페이스를 통해서만 접근 할 수 있으며, Getter만 열려있는 상태이기에 수정자를 통한 멤버 수정이나, 직접 객체의 멤버에 접근해서 수정할 수 있는 방법은 막혔다.

     

    다음과 같은 변경은 객체의 불변성을 보장할까?

    캡슐화를 통해 보장된 불변성은 상속을 사용하는 순간 깨진다.

     

    2) final을 통해 객체의 값 변경을 막자

     

    다음은 Immutale 클래스를 상속받은 extendsImmutable 클래스이다. 

    public class extendsImmutable extends Immutable{
        private String address;
        private String gender;
        private String identityNumber;
    
        public extendsImmutable(String address,String gender,String identityNumber){
            super();
            this.address = address;
            this.gender = gender;
            this.identityNumber = identityNumber;
        }
    
        @Override
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @Override
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        @Override
        public String getIdentityNumber() {
            return identityNumber;
        }
    
        public void setIdentityNumber(String identityNumber) {
            this.identityNumber = identityNumber;
        }
    
        @Override
        public String toString() {
            return "extendsImmutable{" +
                    "address='" + address + '\'' +
                    '}';
        }
    }

     

    1) extendsImmutable은 상속을 받으며 setter를 추가할 수 있고, extendsImmutable Instance는 thread safety를 보장받을 수 없다.

    2) Immutable에서는 정상적이던 동작도 extendsImmutable가 메소드 오버라이딩을 통해 오작동하게 만들 수 있다.

    • 다형성을 통해서 Immutable 객체를 제공 받는다면 이 객체가 Immutable객체인지, 상속을 받은 신뢰할수 없는 객체인지 알기 어렵다.
    • final class로 선언하여 상속을 하지 못하게 함으로써 해결 가능하다.
    public final class Immutable

     

    또 다른 문제에 대하여 생각해보자. 만일, Immutable 클래스에 가족 정보를 나타내는 Family Reference Type을 멤버변수로 추가했다고 해보자. 다음과 같은 코드에서는, 외부에서 getFamily() 호출 시 객체 내부의 참조 값을 넘겨주게 된다. 그리고 객체 외부에서는 그 참조값을 통해서 객체 내부의 맴버를 변경할 수 있게 되어 객체의 불변성을 무너지게 한다.

    public final class Immutable {
        private String address = "대한민국 서울시";
        private String gender = "female";
        private String identityNumber = "9706192034623";
        private Family family = new Family();
    
        public Family getFamily() {
            return family;
        }

     

    3) 생성자나 상태 접근자를 호출 시 DeepCopy를 사용

    이는, DeepCopy를 이용하여 해결 할 수 있다.

    public Family getFamily() {
        return new Family();
    }

    다음과 같이 함수 호출 시마다, 새로운 객체를 생성, 반환하여 외부로부터의 접근을 방지한다.

     

    https://mangkyu.tistory.com/131

     

    [Java] 불변 객체(Immutable Object) 및 final을 사용해야 하는 이유

    클린코드를 읽어도, 이펙티브 자바를 읽어도, 개발을 잘하는 팀의 얘기를 들어도 항상 좋은 코드를 얘기할 때면 불변의 객체를 필연적으로 접하게 되는 것 같습니다. 그래서 이번에는 불변의 객

    mangkyu.tistory.com

     

Designed by Tistory.