문제

다음과 같은 유형의 데이터가 있다고 가정합니다.

class Customer {
  String id; // unique
  OtherCustData someOtherData;
}

class Service {
  String url; // unique
  OtherServiceData someOtherData;
}

class LastConnection {
  Date date;
  OtherConnData someOtherData; // like request or response
}

이제 각 고객이 언제 각 서비스에 연결되었는지 기억해야 합니다.
나는 구조를 만들 것입니다 :

Map<Customer, Map<Service, LastConnection>> lastConnections;

또는 ID로 검색할 수 있고 모든 equal() 및 hashCode()를 작성할 필요가 없습니다.

Map<String, Map<String, LastConnection>> lastConnections;

이제 다음을 통해 LastConnection 데이터에 액세스할 수 있습니다.

LastConnection connection = lastConnections.get(custId).get(srvUrl);

이 모든 것이 보기 흉해 보입니다. 특히 LastConnections 맵의 맵을 기대하는 수십 개의 메서드에 매개 변수로 전달해야 하므로 다음과 같은 자체 클래스를 만들려고 합니다.

class CustomerConnections extends HashMap<String, LastConnection> {
}

class AllConnections extends HashMap<String, CustomerConnections> {
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
}

좋습니다. 상속이 3v1l이라는 것을 이미 배웠으므로 구성을 시도해 보겠습니다.

class CustomerConnections {
    Map<String, LastConnection> customerConnections;
    LastConnection get(String srvUrl) { 
        return customerConnections.get(srvUrl);
    }
    ... // all other needed operations;
}

class AllConnections {
    Map<String, CustomerConnections> allConnections;
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
    public CustomerConnection get(String custId) {
        return allConnections.get(custId);
    }
    ... // all other needed operations;
}

문제는 SOLID 원칙과 모든 모범 사례를 존중하는 최선의 접근 방식이 무엇인지 확신할 수 없다는 것입니다.기존 컬렉션을 확장하는 것 외에는 아무것도 하지 않는 클래스를 만드는 것은 필요 이상으로 엔터티를 늘리는 것처럼 보이지만 코드를 더 명확하게 만듭니다(특히 월별 AllConnections 맵과 같은 다음 레벨이 있는 경우).방향이 있나요?

도움이 되었습니까?

해결책

이미 기존 컬렉션을 확장하는 것 외에는 아무것도하지 않는 클래스 생성

캡슐화로 확장을 변경합니다. 이 정보가 어떻게 저장되는지에 대한 세부 사항을 숨기고 있습니다. 수업의 고객은 고객 연결 기록을 어떻게 제공하는지 알 필요가 없습니다. API의 클라이언트가 코드를 변경하지 않고 기본 모델을 변경할 수 있기 때문에 이것이 좋은 생각이라고 생각합니다.

그러나 내 코드를 더 명확하게 만들 것입니다

이것은 훌륭하고 이것을해야 할 좋은 이유입니다. yourclass.getCustomerConnection (CID)은 yourCollection.get (id) .get (id) .getConnection ()보다 훨씬 명확합니다. 당신은 그 사람 이라도이 코드를 사용하는 사람들의 삶을 더 쉽게 만들어야합니다.

(특히 다음 레벨이있을 때 - 월별 AllConnections의지도 등이 있습니다)

좋아, 당신은 미리 계획하고 코드를 확장 가능하게 만들고있다. 좋은 oo 연습입니다. 제 생각에는 당신이 혼자서 도달 한 동체는 내가 할 것입니다.

다른 팁

이 정보를 저장하기 위한 전용 개체를 만들겠습니다.당신이 만들고 있는 것은 관리자 단순한 컬렉션이 아닌 객체입니다.

않을 것이다 이 정보를 저장하는 방법의 의미가 미래에 변경될 수 있으므로 Map 또는 기타 잘 알려진 컬렉션 클래스에서 파생되도록 만드세요.

대신 고객과 해당 연결을 연결하는 클래스를 구현하고 해당 클래스 내에서 적절한 컬렉션 클래스를 사용합니다(인터페이스와 나머지 코드에 영향을 주지 않고 나중에 자유롭게 변경할 수 있음).

고객/연결 관리자 클래스는 단순한 컨테이너 그 이상입니다.메타데이터(예:이 관계가 언제 확립되었습니까?)필요한 경우 고객 정보가 제공된 연결에서 검색을 수행할 수 있습니다.기본 컬렉션 클래스가 중복 항목을 처리하는 방식이 아닌 필요한 방식으로 중복 항목을 처리할 수 있습니다.등.디버깅/로깅/성능 모니터링을 쉽게 수행하여 진행 상황을 쉽게 이해할 수 있습니다.

또한 컬렉션 사용 방법과 데이터를 얻는 방법도 고려해야한다고 생각합니다.

  • 예를 들어 페이지에 표시 할 간단한 결과 세트 인 경우 표준 컬렉션을 사용하는 것이 합리적으로 보이며 많은 표준 라이브러를 사용하여 조작 할 수 있습니다.
  • 반면에, 변이 가능하고 변경이 지속되어야한다면 (예를 들어) (예를 들어), 자신의 클래스 내에서이를 캡슐화하는 것이 바람직 할 수 있습니다 (데이터베이스에 변경 사항을 쓸 수 있음).

데이터를 어떻게 얻고 지속합니까? 데이터베이스에 저장된 경우 SQL을 사용하여 Datafrstructures를 직접 유지하지 않고 고객 및/또는 서비스 및/또는 월별 최종 연결을 선택할 수 있습니다 (간단한 목록 또는 연결 맵 또는 연결 맵을 반환합니다. ). 또는 각 요청에 대해 쿼리를 실행하고 싶지 않을 수도 있으므로 전체 데이터 구조를 메모리에 유지해야합니다.

캡슐화는 일반적으로 좋은 일입니다. 특히 특히 데메테르의 법칙 - 컬렉션에서 수행 할 작업 중 일부를 AllConnections 클래스 (효과적으로 DAO)로 다시 푸시 할 수 있습니다. 이것은 종종 단위 테스트에 도움이 될 수 있습니다.

또한 사소한 도우미 방법 만 추가하고 싶다는 점을 고려할 때 왜 해시 맵을 여기에서 악으로 간주 하는가? AllConnection의 코드에서 AllConnections는 항상 해시 맵과 같은 방식으로 작동합니다. 다형적으로 대체 가능합니다. 물론, 당신은 잠재적으로 Treemap 등이 아닌 Hashmap을 사용하는 데 잠재적으로 잠재적으로 고정하고 있지만, MAP와 동일한 공개 방법을 가지고 있기 때문에 중요하지 않을 것입니다. 그러나 실제로이 작업을 원하는지 여부는 실제로 컬렉션을 사용하려는 방법에 달려 있습니다. 구현 상속을 자동으로 할인해야한다고 생각하지 않습니다. 언제나 나쁘다 (보통!)

class AllConnections extends HashMap<String, CustomerConnections> {
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
}

사용하지 않는 이유 custId+"#"+srvurl 단순한 열쇠로 Map<String, LastConnection>?

또는 a 튜플 또는 두 개의 ID와 구현이 포함 된 키로 쌍 클래스 hashCode() 그리고 equals() - "가장 깨끗한"OO 솔루션.

왜 그 객체 외부의 객체들 사이의 관계를 유지하고 있습니까?

다음과 같은 것을 제안합니다.

public class Customer 
{
  public List<LastConnection> getConnectionHistory() 
  {
    ... 
  }

  public List<LastConnection> getConnectionHistory(Service service) 
  {
    ...
  }

  public List<LastConnection> getConnectionHistory(Date since) 
  {
    ...
  }
}

public class LastConnection
{
  public Date getConnectionTime() 
  {
    ...
  }

  public Service getService()
  {
    ...
  }
}

그런 다음지나갑니다 List<Customer> 이 정보를 사용하는 방법에.

당신은 그 수업을 만들 수 있습니다 구현 Map<K,V>, 내부적으로 컨테이너 맵에 대표합니다.

class CustomerConnections implements Map<String,LastConnection> {
    private Map<String, LastConnection> customerConnections;

    @Override
    public LastConnection get(Object srvUrl) { 
        return customerConnections.get(srvUrl);
    }
    // all other needed operations;
}

이 접근법의 좋은 점은 당신이 주위를 지나갈 수 있다는 것입니다. Map 표준적이고 잘 정의 된 계약이 있지만, 종종 눈살을 찌푸리는 도서관 클래스를 연장하는 것을 피하십시오.

편집하다 : 아래에서 지적했듯이, 이것은 기본 컬렉션에 대의원을 부족하지 않은 많은 방법을 구현 해야하는 단점이 있습니다.

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