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


14

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

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

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

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

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



5
당신은 더 나은 첫 번째 방법으로 가야합니다 :-정적 공장
Rohit Jain

16
@MarcB op는 싱글 톤을 원하지 않습니다. 그는 같은 클래스의 인스턴스가 많이있을 수 있지만 이러한 인스턴스는 식별 가능해야합니다.

1
@MarcB 싱글 톤 패턴을 알고 있지만 클래스의 인스턴스 하나만 가능하다고 생각합니까? 여러 인스턴스, 다른 값을 원합니다. 질문이 명확하지 않으면 죄송합니다. 편집 : 게시하기 전에 첫 번째 의견 만 보았습니다.
Peanut

2
I'm aware that one way of doing this is to have a static factory that holds a Map...왜 이런 식으로하고 싶지 않습니까?
FrustratedWithFormsDesigner

답변:


13

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

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

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

편집 :-

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


1
그것은 OP가 이미 생각한 것입니다.
BGurung

OP의 관심사 중 일부를 명확하게 해결하는 것으로 보입니다.
Robert Harvey

@RobertHarvey. 그래, 그 책은 이것들과 같은 대부분의 주제를위한 최고의 소스입니다. 그리고 그것은 실제로 첫 번째 항목입니다. :)
Rohit Jain

효과적인 자바 +1, 사실 :) 그러나 나는 고유성을 달성하는 다른 방법에 관해서는 그냥 궁금했다 지금 내 가방에 앉아 책을 가지고 할 떨어져 정적 공장 / 정적 메서드와 생성자에서 예외에서. 아무것도 없다면 나는 이것을 받아 들일 것이다.
Peanut

@땅콩. 확실한. 더 많은 정보를 얻기 위해 파는 최고의 리소스입니다.
Rohit Jain

5

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

  • 효과적인 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으로 해시 맵 등에서 클래스를 사용할 수 있으며 정확히 같은 인스턴스 일 필요는 없습니다 .


예, 부탁합니다.
Robert Harvey

적절한 구현의 @RobertHarvey 예?
weston

당신이 하나를 제공 한 것 같습니다. 그러나 정적 팩토리 메소드에서 Name 속성이 동일한 지 확인하는 것과 다른 점이 명확하지 않습니다.
Robert Harvey

1
@RobertHarvey 나는 더 많은 것을 설명하려고 노력했지만 정적 팩토리가 전혀 필요없는 완전한 대안을 제시하고 있으며 이름 당 인스턴스를 두 번 이상 원하지 않는 OP 시작점에 도전하고 있습니다.
weston

고유 한 객체가 필요한 유효한 이유는 동기화 된 블록이 객체를 모니터로 사용하기를 원하기 때문입니다. 서로 .equals () 두 개체가 작동하지 않습니다.
리 콜드웰

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

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

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

throw객체를 반환하는 대신 동일한 이름이 존재하거나 객체를 반환하는 경우 팩토리 메서드를 사용하여 메모리 누수가 발생하지 않습니다 null.
Robert Harvey

@RobertHarvey 나는 실제로 누출되지는 않지만 합법적 인 객체 (소위 "지체")를 의미합니다. 간단한 정적 맵은 값 객체가 해제되는 것을 방지하는 반면, 약한 참조의 맵은 다른 라이브 참조가 존재하는 한 메모리에 유지됩니다.
dasblinkenlight

아 무슨 말인지 알 겠어 이것은 드문 경우 중 하나 일 수 있습니다 destructor.
Robert Harvey

1
너무 복잡합니다. @weston answer와 같이 수행 할 수 있으며, equals를 재정의하고 공장에서 이름을 수집하도록하십시오.
Tulains Córdova

@ user1598390 일을 가능한 한 단순하게해야하지만 더 단순하지 않아야합니다. weston의 "솔루션"은 OP의 문제를 해결하지 못하며 (지도는 없음) 이름 모음은 느린 메모리 누수를 생성합니다 (예, Java에는 메모리 누수가 있음).
dasblinkenlight

1

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


질문의 세 번째 단락에서 내가 말한 것을 반복했습니다. 나는 다른 길을 갔다.
Peanut

죄송합니다. 게시물을 게시하기 전에 답변을 확인했기 때문에 거의 동시에 답변 한 것 같습니다. 실제로 StackOverflown에서 마이그레이션하려고 시도했지만 응답하지 않았습니다.
HericDenis

1

다음을 시도하십시오. 생성 한 각 개체를 추적해야합니다. 이를 위해 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;
        }
    }

이것은 자바가 아니십니까? 의사 코드를 작성 했습니까? 아니면 다른 언어로? 명시 적으로 지정하십시오.
Rohit Jain

C #처럼 보입니다. Akshay, 이외의 다른 컬렉션을 배워야 List합니다. 이것은에 적합합니다 Dictionary<string,UniqueName>.
weston
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.