클래스의 고유 인스턴스를 보장하는 방법은 무엇입니까?

주어진 클래스의 각 인스턴스가 고유하게 식별 가능한 인스턴스인지 확인하는 다른 방법을 찾고 있습니다.

예를 들어, Name필드 가있는 클래스가 있습니다 name. John Smith Namename초기화 된 객체가 있으면 John Smith Name라는 이름으로 다른 객체 를 인스턴스화 할 수 있기를 원하지 않거나 인스턴스화가 발생하면 원래 객체에 대한 참조가 오히려 다시 전달되기를 원합니다. 새로운 물체보다.

이 작업을 수행하는 한 가지 방법은 Map현재의 모든 Name 객체 를 보유하는 정적 팩토리를 유지하는 것이며 팩토리는 John Smith를 가진 객체가 이름으로 존재하지 않는지 확인합니다. Name목적.

내 머리 꼭대기에서 생각할 수있는 또 다른 방법은 Name클래스에 정적 맵이 있고 전달 된 값 name이 이미 다른 객체에서 사용중인 경우 생성자가 예외를 던지는 호출 할 때 예외가 발생 한다는 것을 알고 있습니다 생성자에서는 일반적으로 나쁜 생각 입니다.

이것을 달성하는 다른 방법이 있습니까?



답변

실제로 당신은 이미 당신의 질문에 대답했습니다. 첫 번째 방법이 더 효과적입니다. 생각하는 것 static factory보다 항상 사용하는 것이 좋습니다 constructor. 따라서이 Constructor경우 사용 을 피할 수 있습니다 . 그렇지 않으면 throw some exception지정된 이름의 인스턴스가 이미 존재하는 경우가 있습니다.

그래서, 당신은 정적 팩토리 메소드 생성 할 수 있습니다 : – getInstanceWithName(name)그 이름으로 이미 인스턴스를 얻을 것이다, 그것은 존재하지 않는 경우, 그것은 새로운 인스턴스를 생성합니다, 당신은 할 constructor다루는 경우가 대부분 수행해야합니다으로, 개인 static factories.

또한 클래스 에서 정적 List또는 Map생성 된 모든 고유 인스턴스 를 유지해야합니다 Factory.

편집 :-

당신은 확실히 효과적인 Java- 항목 # 1을 거쳐야합니다 : 생성자보다 정적 팩토리를 고려하십시오 . 그 책보다 더 나은 설명을 얻을 수 없습니다.


답변

효과적인 자바에 대한 언급은 많은 신뢰성을 추가하는 것으로 보이므로이 답변은 다음과 같습니다.

  • 효과적인 Java 항목 8 : 동일 항목을 재정의 할 때 일반 계약 준수
  • 효과적인 Java 항목 9 : equals를 재정의 할 때 항상 hashCode를 재정의하십시오.
  • 효과적인 Java 항목 15 : 변경 가능성 최소화

이 이름 객체의 인스턴스가 두 개 이상인 경우 한 단계 뒤로 물러서서 왜 관심이 있는지 궁금합니다.

이런 종류의 객체 풀링을 거의 할 필요가 없습니다. OP 가이 작업을 수행하고 있기 때문에 Name객체와 단순히 객체를 비교할 수 있습니다 ==. 또는 키와 비슷한 Name내부 의 객체를 사용하십시오 HashMap.

그렇다면 이것은의 적절한 구현을equals() 통해 해결할 수있는 것입니다 .

이렇게 :

public final class Name {
  private final String name;

  public Name(String name) {
    if (name == null) {
      name = ""; //or exception if you like
    }
    this.name = name;
  }

  public String getName() {
    return name;
  }

  @Override
  public boolean equals(Object o) {
    if (!(o instanceof Name)) {
      return false;
    }
    Name other = (Name) o;
    return other.name.equals(name);
  }

  @Override
  public int hashCode() {
    return name.hashCode();
  }
}

완료되면 다음이 적용됩니다.

Name a = new Name("weston");
Name b = new Name("weston");
assert(a.equals(b)); //same but:
assert(a!=b); //not the same instance
//test out the Name instances in a hashmap:
HashMap<Name,Object> map = new HashMap<Name,Object>();
Object detailsIn = new Object();
map.put(a,detailsIn);
Object detailsOut = map.get(b);
assert(detailsIn==detailsOut); //the map returned the same details object
//even though we put with `a` and got with `b` thanks to our correct equals implementation

나는 당신의 목표를 추측하고 있지만,이 방법 Name으로 해시 맵 등에서 클래스를 사용할 수 있으며 정확히 같은 인스턴스 일 필요는 없습니다 .


답변

  • Name인터페이스 만들기
  • NameFactory메소드를 사용 하여 인터페이스 작성Name getByName(String)
  • 의 구현을 작성 NameFactoryMap<String,WeakReference<Name>>그 안에
  • synchronizegetByName새로운 인스턴스를 만들기 전에 메소드 내부의 이름으로 맵에Name
  • 선택적으로, 구현 Name내부 에서 인터페이스 의 정적 개인 구현을 사용 하십시오.NameFactory

이 접근 방식을 통해 다음을 보장 할 수 있습니다.

  • Name언제든지 하나의 인스턴스 만 존재합니다.
  • 수업 Name시간에 필요한 것보다 더 오래 붙을 때 “Lingerer”메모리 누수가 발생하지 않습니다.
  • 인터페이스를 사용하기 때문에 모의 객체로 디자인을 테스트 할 수 있습니다.

답변

getNameInstance(String)같은 이름을 가진 객체가 이미 존재한다면 (예를 들어 정적 클래스의 hastable을 기반으로) 생성자를 private로 만들고 메소드 를 만들어야합니다. 해시 테이블에


답변

다음을 시도하십시오. 생성 한 각 개체를 추적해야합니다. 이를 위해 List를 사용하고 있습니다. 클래스 생성자를 비공개로 설정하여 인스턴스를 만들기 전에 사전 확인을 적용 할 수 있습니다.

class UniqueName
    {
        private string Name;
        public int ID;
        private static int Count=0;
        static List<UniqueName> lt=new List<UniqueName>();

        private UniqueName(string Name)
        {
            this.Name = Name;
            ID = ++Count;
        }

        public static UniqueName GetUniqueueInstance(string Name)
        {
            foreach (UniqueName un in lt)
            {
                if ( string.Compare( un.Name,Name,StringComparison.InvariantCultureIgnoreCase)==0)
                    return un;
            }

            UniqueName temp=new UniqueName(Name);
            lt.Add(temp);
            return temp;
        }
    }


답변