문제

나는 돌연변이와 불변의 물체를 돌려 주려고 노력하고 있습니다. Mutable 객체를 사용하면 많은 나쁜 프레스가 발생하지만 (예 : 방법에서 다양한 문자열을 반환) 부정적인 영향이 무엇인지 이해하는 데 어려움이 있습니다. 돌연변이 가능한 객체를 사용하는 모범 사례는 무엇입니까? 가능할 때마다 피해야합니까?

도움이 되었습니까?

해결책

글쎄, 이것에는 몇 가지 측면이 있습니다. 1 번, 기준 식별이없는 변이 가능한 물체는 홀수 시간에 버그를 유발할 수 있습니다. 예를 들어, 고려하십시오 Person 가치 기반의 콩 equals 방법:

Map<Person, String> map = ...
Person p = new Person();
map.put(p, "Hey, there!");

p.setName("Daniel");
map.get(p);       // => null

그만큼 Person 인스턴스는 키로 사용될 때지도에서 "손실"을받습니다. hashCode 평등은 돌연변이 가능한 값에 기초했습니다. 이러한 값은지도 밖에서 변경되었고 해싱은 모두 쓸모 없게되었습니다. 이론가들은이 시점에서 하프를 좋아하지만 실제로는 그것이 너무 많은 문제라는 것을 알지 못했습니다.

또 다른 측면은 코드의 논리적 "합리성"입니다. 이것은 가독성에서 흐름에 이르기까지 모든 것을 포함하는 정의하기 어려운 용어입니다. 일반적으로 코드를보고 코드를 쉽게 이해할 수 있어야합니다. 그러나 그보다 더 중요합니다. 바르게. 객체가 다른 코드 "도메인"에서 독립적으로 변경 될 수있을 때, 때로는 어디에 그리고 이유를 추적하기가 어려워집니다 ( "거리에서의 으스스한 동작"). 이것은 예시하기가 더 어려운 개념이지만, 더 크고 더 복잡한 아키텍처에서 종종 직면하는 것입니다.

마지막으로, 돌연변이 가능한 물체입니다 살인자 동시 상황에서. 별도의 스레드에서 변이 가능한 객체에 액세스 할 때마다 잠금을 처리해야합니다. 이것은 처리량을 줄이고 코드를 만듭니다 극적으로 유지하기가 더 어렵습니다. 충분히 복잡한 시스템은이 문제를 지금까지 비례하지 않아 유지하는 것이 거의 불가능 해집니다 (동시 전문가조차도).

불변의 물체 (특히 불변의 컬렉션)는 이러한 모든 문제를 피하십시오. 일단 당신이 그들이 어떻게 작동하는지에 대한 마음을 얻으면, 당신의 코드는 읽기 쉽고, 유지하기가 더 쉬우 며, 이상하고 예측할 수없는 방식으로 실패 할 가능성이 줄어 듭니다. 불변의 물체는 쉬운 조롱 가능성뿐만 아니라 시행하는 경향이 있기 때문에 테스트하기가 훨씬 쉽습니다. 요컨대, 그들은 주변의 좋은 연습!

그 말로, 나는이 문제에서 열심이 거의 없습니다. 모든 문제는 모든 것이 불변 할 때 잘 모델링되지 않습니다. 그러나 나는 당신이 이것을 10 개의 의견으로 만드는 언어를 사용하고 있다고 가정 할 때 가능한 한 많은 코드를 그 방향으로 밀어 붙여야한다고 생각합니다 (c/c ++는 Java와 마찬가지로 이것을 매우 어렵게 만듭니다). . 간단히 말해서, 장점은 당신의 문제에 대해 다소 의존하지만, 나는 불변성을 선호하는 경향이 있습니다.

다른 팁

불변의 물체 대 불변의 컬렉션

Mutable 대 불변의 대상에 대한 토론에서 더 미세한 요점 중 하나는 불변성의 개념을 컬렉션으로 확장 할 수 있다는 것입니다. 불변의 물체는 종종 단일 논리적 데이터 구조 (예 : 불변의 문자열)를 나타내는 객체입니다. 불변의 물체에 대한 언급이 있으면 물체의 내용이 변경되지 않습니다.

불변의 컬렉션은 결코 변하지 않는 컬렉션입니다.

Mutable 컬렉션에서 작업을 수행 할 때 컬렉션을 제자리에 변경하면 컬렉션에 대한 참조가있는 모든 엔티티가 변경 사항을 볼 수 있습니다.

불변의 컬렉션에서 작업을 수행하면 변경 사항을 반영하는 새로운 컬렉션으로 참조가 반환됩니다. 이전 버전의 컬렉션에 대한 참조가있는 모든 엔티티는 변경 사항이 보이지 않습니다.

영리한 구현이 불변성을 제공하기 위해 전체 컬렉션을 복사 (복제) 할 필요는 없습니다. 가장 간단한 예는 단일 링크 된 목록 및 푸시/팝 작업으로 구현 된 스택입니다. 새 컬렉션의 이전 컬렉션의 모든 노드를 재사용하여 푸시를위한 단일 노드 만 추가하고 POP에 대한 노드를 복제 할 수 있습니다. 반면에 단일 링크 된 목록의 Push_Tail 작업은 그렇게 간단하거나 효율적이지 않습니다.

불변 대 변수 변수/참조

일부 기능 언어는 불변성의 개념을 사용하여 단일 참조 할당 만 허용합니다.

  • Erlang에서 이것은 모든 "변수"에 해당됩니다. 객체를 참조에 한 번만 할당 할 수 있습니다. 컬렉션에서 작동한다면 새 컬렉션을 이전 참조 (변수 이름)로 재 할당 할 수 없습니다.
  • Scala는 또한 모든 참조가 var 또는 , VAL은 단일 할당과 기능적 스타일을 홍보하지만 VAR은보다 C와 유사하거나 Java와 같은 프로그램 구조를 허용합니다.
  • VAR/VAL 선언은 필요하지만 많은 전통적인 언어는 다음과 같은 선택 수정자를 사용합니다. 결정적인 자바에서 Const c.

개발의 용이성 대 성능

거의 항상 불변의 대상을 사용하는 이유는 코드에 대한 부작용 무료 프로그래밍 및 간단한 추론 (특히 동시에 동시/병렬 환경)을 홍보하는 것입니다. 객체가 불변이없는 경우 다른 엔티티가 기본 데이터를 변경하는 것에 대해 걱정할 필요가 없습니다.

주요 단점은 성능입니다. 다음은 글이 있습니다 내가 Java에서 한 간단한 테스트 장난감 문제에서 불변과 돌연변이 가능한 물체를 비교합니다.

성능 문제는 많은 애플리케이션에서 무의미하지만 전부는 아니기 때문에 Python의 Numpy Array 클래스와 같은 많은 대형 숫자 패키지가 큰 배열의 내부 업데이트를 허용하는 이유입니다. 이것은 대형 행렬 및 벡터 작업을 사용하는 응용 분야에 중요합니다. 이러한 대규모 데이터 평행 및 계산 집약적 인 문제는 제자리에 작동함으로써 빠른 속도를 달성합니다.

이 블로그 게시물을 확인하십시오. http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html. 불변의 물체가 왜 변한 것보다 낫다는 이유를 설명합니다. 요컨대 :

  • 불변의 물체는 구성, 테스트 및 사용하기가 더 간단합니다.
  • 진정으로 불변의 물체는 항상 실로 안전합니다
  • 그들은 시간적 결합을 피하는 데 도움이됩니다
  • 사용량은 부작용이 없습니다 (방어 사본 없음)
  • 정체성 돌연변이 문제를 피합니다
  • 그들은 항상 실패 원자력이 있습니다
  • 캐시가 훨씬 쉽습니다

불변의 대상은 매우 강력한 개념입니다. 그들은 모든 고객에게 대상/변수를 일관성있게 유지하려는 많은 부담을 빼앗아갑니다.

CPoint 클래스와 같은 낮은 수준의 비 폴리 흉부 대상에 사용할 수 있습니다.

또는 수학적 함수를 나타내는 ifunction과 같은 높은 수준의 다형성 인터페이스에 사용할 수 있습니다.

가장 큰 장점 : 불변성 + 객체 의미론 + 스마트 포인터는 객체 소유권을 비 문제로 만들고, 객체의 모든 클라이언트는 기본적으로 자신의 개인 사본을 가지고 있습니다. 암시 적으로 이것은 또한 동시성의 존재 하에서 결정 론적 행동을 의미한다.

단점 : 많은 데이터가 포함 된 객체와 함께 사용하면 메모리 소비가 문제가 될 수 있습니다. 이에 대한 해결책은 물체에서 상징적 인 작업을 유지하고 게으른 평가를 수행하는 것입니다. 그러나 이로 인해 인터페이스가 상징적 작업을 수용하도록 설계되지 않은 경우 성능에 부정적인 영향을 줄 수있는 상징적 계산의 사슬로 이어질 수 있습니다. 이 경우에 확실히 피해야 할 것은 방법에서 엄청난 메모리 덩어리를 반환하는 것입니다. 사슬 된 상징적 작업과 함께 이것은 대규모 메모리 소비와 성능 저하로 이어질 수 있습니다.

따라서 불변의 대상은 분명히 객체 지향 디자인에 대한 나의 주요 사고 방식이지만 교리는 아닙니다. 그들은 객체의 클라이언트를 위해 많은 문제를 해결하지만 특히 구현자를 위해 많은 문제를 만듭니다.

당신이 말하는 언어를 지정해야합니다. C 또는 C ++와 같은 저수준 언어의 경우, 상호 객체를 사용하여 공간을 보존하고 메모리 휘트를 줄이는 것이 좋습니다. 고급 언어에서 불변의 객체는 "거리에서 으스스한 동작"이 없기 때문에 코드의 동작 (특히 다중 스레드 코드)에 대해 쉽게 추론 할 수 있습니다.

Mutable Object는 단순히 생성/인스턴스화 후 수정할 수있는 객체입니다. 수정할 수없는 불변의 객체입니다 ( Wikipedia 페이지 주제에 대해). 프로그래밍 언어의 예는 Pythons 목록과 튜플입니다. 튜플은 할 수없는 반면 목록을 수정할 수 있습니다 (예 : 새 항목을 작성한 후 새 항목을 추가 할 수 있음).

나는 모든 상황에서 어느 것이 더 나은지에 대한 명확한 대답이 있다고 생각하지 않습니다. 그들은 둘 다 장소가 있습니다.

클래스 유형이 변경 가능하면 해당 클래스 유형의 변수는 여러 가지 다른 의미를 가질 수 있습니다. 예를 들어, 객체를 가정하십시오 foo 필드가 있습니다 int[] arr, 그리고 그것은 a에 대한 참조를 가지고 있습니다 int[3] 숫자 {5, 7, 9} 필드의 유형이 알려져 있지만, 적어도 네 가지 다른 것들이 있습니다.

  • 잠재적으로 공유되는 참조, 홀더가 값 5, 7 및 9를 캡슐화하는 것만 관리하는 모든 사람의 참조. foo 원한다 arr 다른 값을 캡슐화하려면 원하는 값을 포함하는 다른 배열로 바꿔야합니다. 사본을 만들고 싶다면 foo, 하나는 사본을 참조 할 수 있습니다. arr 또는 {1,2,3} 값을 보유한 새로운 배열은 더 편리합니다.

  • 우주의 어느 곳에서나 값 5, 7 및 9를 캡슐화하는 배열에 대한 유일한 참조. 만약에 foo 값 5, 8 및 9를 캡슐화하려면 해당 배열의 두 번째 항목을 변경하거나 값 5, 8 및 9를 고정하는 새 배열을 만들고 이전 항목을 포기할 수 있습니다. 사본을 만들고 싶다면 foo, 하나는 사본을 교체해야합니다 arr 새로운 배열에 대한 참조로 foo.arr 우주의 어느 곳에서나 해당 배열에 대한 유일한 참조로 남아 있습니다.

  • 일부가 소유 한 배열에 대한 참조 다른 노출 된 물체 foo 어떤 이유로 든 (예 : 아마도 원할 것입니다 foo 일부 데이터를 저장하려면). 이 시나리오에서 arr 배열의 내용을 캡슐화하지 않고 오히려 신원. 교체하기 때문에 arr 새로운 배열을 참조하여 그 의미, 사본은 foo 동일한 배열에 대한 참조를 유지해야합니다.

  • 배열에 대한 참조 foo 유일한 소유자이지만 어떤 이유로 다른 객체에 의해 참조가 보관됩니다 (예 : 다른 개체를 보관하여 데이터를 저장하기를 원합니다. 이 시나리오에서 arr 배열의 정체성과 그 내용을 모두 캡슐화합니다. 교체 arr 새로운 배열을 참조하면 의미가 완전히 바뀌지 만 복제품이 있습니다. arr 인용하다 foo.arr 그 가정을 위반할 것입니다 foo 유일한 소유자입니다. 따라서 복사 할 방법이 없습니다 foo.

이론에 의하면, int[] 좋은 간단한 잘 정의 된 유형이어야하지만 네 가지 매우 다른 의미가 있습니다. 대조적으로, 불변의 대상에 대한 언급 (예 : String) 일반적으로 하나의 의미 만 있습니다. 불변의 물체의 "힘"의 대부분은 그 사실에서 비롯됩니다.

배열 또는 문자열의 참조를 반환하면 외부 세계가 해당 객체의 내용을 수정하여 변이 가능 (수정 가능한) 객체로 만듭니다.

불변의 수단을 변경할 수 없으며 변이 할 수있는 수단은 변경할 수 있습니다.

객체는 자바의 원시인과 다릅니다. 프리미티브는 유형 (부울, int 등)에 내장되어 있으며 객체 (클래스)는 사용자가 만든 유형입니다.

클래스 구현 내에서 멤버 변수로 정의 될 때 프리미티브 및 객체는 변이 가능하거나 불변 할 수 있습니다.

많은 사람들이 최종 수정자를 갖는 프리미티브와 객체 변수가 불변이라고 생각하지만 이것은 사실이 아닙니다. 따라서 최종은 거의 변수에 불변을 의미하지는 않습니다. 여기 예를 참조하십시오
http://www.siteconsortium.com/h/d0000f.php.

변하기 쉬운 인스턴스는 참조로 전달됩니다.

불변 인스턴스는 가치로 전달됩니다.

추상 예. 그것이 명명 된 파일이 있다고 가정합니다 txtfile 내 HDD에서. 이제 물어볼 때 txtfile 나에게서 두 가지 모드로 반환 할 수 있습니다.

  1. 바로 가기를 만듭니다 txtfile 그리고 PAS 바로 가기, 또는 또는
  2. 사본을 가져 가십시오 txtfile 그리고 PAS 사본.

첫 번째 모드에서 돌아 왔습니다 txtfile 바로 가기 파일을 변경할 때 원본 파일도 변경하기 때문에 변한 파일입니다. 이 모드의 장점은 각각의 반환 된 단축키가 더 적은 메모리 (RAM 또는 HDD)가 필요하다는 점이며, 단점은 모든 사람 (나뿐만 아니라 소유자)이 파일 컨텐츠를 수정할 권한이 있다는 것입니다.

두 번째 모드에서 돌아 왔습니다 txtfile 수신 된 파일의 모든 변경 사항은 원본 파일을 참조하지 않기 때문에 불변 파일입니다. 이 모드의 장점은 나 (소유자)만이 원본 파일을 수정할 수 있다는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top