値タイプと不変オブジェクト

16131 ワード

値タイプは、複雑なオブジェクトの世界を単純化するために作成された概念です.
したがって、価格タイプは簡単で安全でなければなりません.

共有値タイプを参照


Address address = new Address("city", "street", "10000");

Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);

member member2 = new Member();
member2.setUsername("member2");
member2.setHomeAddress(address);
em.persist(member2);

// member1이 아닌 member 객체의 city만 바꾸고 싶어!
member.getHomeAddress().setCity("newCity");

// 그러나 member와 member2의 city가 모두 newCity로 바뀐다.
// 이런 버그는 찾아내기가 힘들다.
// 지금이야 바로 밑에 코드를 작성했지만 실제로는 한참떨어진 곳에 작성하므로
上記のコードから、imbeddyタイプのような値タイプを複数のシンボルで共有することは危険であることがわかる.このような予期せぬ副作用が発生する可能性があり、デバッグが困難です.

値タイプの深度コピー

Address address = new Address("city", "street", "10000");

Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);

// 깊은 복사
Address copyAddress = new Address(address.getCity(),
                                  address.getStreet(), 
                                  address.getZipcode());
                                  
Member member2 = new Member();
member2.setUsername("member2");
member2.setHomeAddress(copyAddress);
em.persist(member2);

// 이렇게 하면 member의 city만 변하게 된다.
member.getHomdAddress().setCity("newCity");
価値タイプの共有参照は危険です.
逆に、参照値をコピーするのではなく、値をコピーする深いコピーを使用すると、副作用が解消されます.

オブジェクトタイプの制限


1.デフォルトのタイプは値をコピーします。

int a = 10;
int b = a;
b = 4;

System.out.println(a); // 10
System.out.println(b); // 4

2.オブジェクトタイプ参照値をコピーします。

Address a = new Address("old");
Address b = a; // 객체 타입은 참조값을 복사한다.
b.setCity("new");

System.out.println(a.getCity()); // new
System.out.println(b.getCity()); // new
  • 深いレプリケーションを頻繁に使用すると、共有参照による副作用を防止することができる.
  • の問題は、imbeddyタイプのように直接定義された値タイプがjavaの基本タイプではなく、オブジェクトタイプであることです.
  • オブジェクトタイプなので、深度コピーを強制することはできません.つまり、オブジェクトの共有参照は避けられない!!
  • 不変オブジェクト


    [Address]
    @Getter
    @AllArgsConstructor
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    @Embeddable
    public class Address {
        
        private String city;
        private String street;
        private String zipcode;
        
        public Address(String city, String street, String zipcode) {
            this.city = city;
            this.street = street;
            this.zipcode = zipcode;
        }
    }
    [JpaMain]
    Address address = new Address("city", "street", "10000");
    
    Member member = new Member();
    member.setUsername("member1");
    member.setHomeAddress(address);
    em.persist(member);
    
    Address newAddress = new Address("newCity", 
                                      address.getStreet(),
                                      address.getZipCode());
    member.setHomeAddress(newAddress);
  • オブジェクトタイプを変更できない場合は、ソースから副作用が遮断されます.
  • 値タイプは、不変オブジェクト(可変オブジェクト)として設計する必要があります.
  • 不変オブジェクトは、作成時から値を絶対に変更できないオブジェクトです.
  • 方法の1つは、
  • ジェネレータのみを使用して値を設定し、モディファイヤを作成しないことです.
  • はまた、修正者をプライベート化することもできる.
  • :Integer、StringはJavaが提供する典型的な不変オブジェクトであることを参照してください.
  • 不変の小さな制約によって、副作用という大きな災難を防ぐことができる.