이 항목에서는 불변 클레스에 대해서 이야기 하고 있는데요. 불변, 가변이 무엇이냐 부터 짚고 넘어갈께요

가변 可變
사물의 모양이나 성질이 바뀌거나 달라질 수 있음. 또는 사물의 모양이나 성질을 바꾸거나 달라지게 할 수 있음.

불변 不變
사물의 모양이나 성질이 변하지 아니함. 또는 변하게 하지 아니함.

라고 하네요 네이버 펌질 'ㅁ'

가변의 가는 가능하다 할때 가 이구요 변은 변신! 할때 변 입니다. 불변의 불은 불가능 할때 불 입니다.

이제 이해가 가십니까?
가변성을 최소화 하자는것은 변하는게 가능한 성질을 최소화 하자.
즉 값을 못바꾸게 하자! 라는것이고

불변 클레스는 값이 변하지 않는 클레스 라는겁니다.

이딴걸 난 쓴적도 없는데 왜 이런 항목이 있느냐. 라고 말하신다면 자바를 하고있다면 이미 쓰고있습니다.
바로 String 클레스. 이놈이 가장 대표적인 불변클레스입니다.

예를들어 문자열의 일부분을 치환하고 싶다 라고하면 String.replaceAll 같은 메소드를 사용할겁니다.
근데 이게 내가 원하는 객체가 바뀌는것이 아니라 그것이 바뀐 객체를 리턴해줍니다.
따라서 무슨짓을해도 한번 만든 String 객체는 바꿀수가 없는거죠. 바로 이게 불변 클레스 입니다.

일단 불변 클레스에 대한 간단한 설명은 여기까지 하고 불변 클레스를 만들기 위한 다섯가지 규칙을 알려드리겠습니다.

  • 객체의 상태를 변경하는 그 어떤 메소드(변경자라고 하는)도 제공하지 않는다.
  • 상송을 할수 없도록 하자. (public final class 라고 클레스를 선언하면 상속이 불가능하다.)
  • 모든 필드를 final 로 지정한다.
  • 모든 필드를 private로 지정한다.
  • 가변 컴포넌트의 직접적인 외부 접근을 막자.

위의 다섯가지 항목이 있는데 각각 설명을 해보겠습니다.

-일단 불변 클레스라고 했으니까 당연히 변경하도록 하는 메소드가 있으면 안됩니다.
-혹시 상속해서 건드릴지도 모르고 나중에 상속받은 클레스가 상속한 클레스로 업케스팅 하게되면 이게 원래의 불변클레스인지 상속받아서 뜯어고친놈인지 구분 하기도 힘들다.
-모든 필드를 final로 해두면 값을 변경할수 없으니까 당연히 불변
-모든 필드를 private라고 해두면 외부에서 볼수 없으니까 불변

문제의 마지막 항목입니다.
가변 컴포넌트의 직접적인 외부 접근을 막자.
음.. 일단 가변은 위에서 말했고. 직접적인... 은 모를리 없고 접근을 막자... 도 압니다.
근데 컴포넌트가 뭐여?

컴포넌트[ Component ]
소프트웨어 개발을 마치 레고(Lego) 블록을 쌓듯이 쉽게 할 수 있도록 하는 기술을 말한다.즉, 기존의 코딩 방식에 의한 개발에서 벗어나 소프트웨어 구성단위(module)를 미리 만든 뒤 필요한 응용 기술을 개발할 때 이 모듈을 조립하는 기술을 말한다. 컴포넌트 기술을 활용하면 복잡한 정보 시스템을 신속하게 구축할 수 있으며, 유사한 정보 시스템을 구축할 때 재사용이 가능한 장점이 있다. 특히, 급속도로 변하는 인터넷 환경에서 표준화된 소프트웨어를 만드는 것이 필요하기 때문에 컴포넌트는 매우 중요하다. 이미 국가 차원에서 소프트웨어의 컴포넌트화를 추진하고 있는 미국은 소프트웨어의 컴포넌트화로 개발생산성이 10배, 품질보증이 16배씩이나 증가했다는 보고가 있다. 국내에서는 한국소프트웨어 컴포넌트 컨소시엄(KCSC)이 발족돼 2002년까지 3,000개의 공용 컴포넌트를 개발하기로 하였으며, 정부는 표준화를 통해 연평균 약 100%의 고성장이 예상되는 소프트웨어 컴포넌트 산업을 적극 육성하기로 했다.

는 아닌거 같죠?

항목16에서 설명할텐데 항목 8. equals 메소드를 오버라이딩 할때는 보편적 계약을 따르자. 에서도 잠깐 다루었습니다.(ColorPoint)

다른 클레스의 객체를 필드(맴버변수)로 사용하는걸 두고 컴포넌트라고 부르는거 같습니다.

final class ColorPoint{
	private final Point p;
	private final Color c;
}

그러니까 ColorPoint에서  p와 c가 컴포넌트인데 이때 ColorPoint가 불변 클레스다. 근데 getPoint 로 p를 밖에서 받을수 있어요. 그런다음에 x,y 좌표를 바꾸면?
의미가 업ㅂ엉...
이때 굳이 getPoint, getColor 을 만들겠다 라고 한다면 항목 11. clone 메소드는 신중하게 오버라이드 하자 에서 나왔던 복사clone 나 복사생성자를 사용해서 넘겨주도록 하자. 복사해서 넘겨준다면 뭐 그걸가지고 지지든 볶든 상관이 없겠죠
아니면 Point와 Color 또한 불변클레스로 만들어 버리는겁니다.
또하나 귀찬은것은 배열이나 Collection 같은놈들.. 이놈들도 복사해서 넘겨주던 불변으로 만들던 해야겠습니다. 알아서 하세영 ㅠㅠ

메소드를 만들때 참조해야할것은 예를들어 add 를 한다고 가정해봅시다.
int a,b,c;
a=b+c; 라고 한다면 이 과정에서 b와 c의 내용이 바뀌지 않는다. 이것도 일종의 불변이라고 볼수도 있겠다.
BigInteger,BigDecimal이라는 클레스가 있는데 (모른다면 한번 써보자 값의 범위가 거의 제한이 없이 정수, 실수 연산을 할수있다)

어떤 값을 표현하는 클레스이기 때문에
BigInteger a,b,c 가 있다면
a=b.add(c); 일때 b나 c가 변경되면 말이 안된다.
이때 add 메소드는 새로운 BigInteger 객체를 만든다음 거기에 a와 b를더한 값을 넣어주고 새로만든놈을 리턴해준다.
이렇게 하면 a와 b는 절대로 변하지 않으면서 우리가 원하는 연산을 할수있다.

하지만 문제가 있다. 만약 엄청나게 큰 불변 데이터의 매우 작은 일부만 변경해서 다시 쓰려면?
이때도 새로운 객체가 생성된다. 내가 원하는 부분만 수정해서 사용할수가 없다는거다. 그래서 불변클레스에는 가변 클레스가 따라붙는다. String 에는 StringBuilder(요즘은 StringBuffer대신 사용됨) BigInteger에는 BitSet이라는게 있다.

String 에서 + 연산은 편하지만 반복적인 작업에는 항상 새로운 객체를 생성하기 때문에 비효율적이다. 
따라서 그것을 보완하기 위해서 StringBuilder의 append 같은 메소드가 사용된다.

또한 BigInteger의 비트연산같은 경우에도 항상 새로운 객체가 생성되기 떄문에 BitSet을 사용하면 그 객체를 직접 변경할수 있다.

 하여튼 데이터를 처리할때 이것이 가변 클레스로 만들것인지 불변 클레스로 만들것인지에 대해서 조금 고민을 해봐야 할것이다.
가변클레스가 만들기는 쉽지만 이상한데서 사람을 골치아프게 만들지도 모르기 때문이다. 

Posted by 동적할당
: