假设我有以下类型的数据:

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;

或者,能够通过 ids 进行搜索而不必编写所有 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)获得(ID).getConnection()更清晰。你需要让使用此代码更容易在人的生活中,即使你的那个人。

  

(特别是当有下一个水平 - 像地图按月等AllConnections的)

好,那么你提前计划,使你的代码扩展。这是很好的做法OO。在我看来,你已经在你自己达到conculsion是我会怎么做。

其他提示

我会为存储该信息创建专用对象。你正在创建一个管理的对象,而不是简单的集合。

我的不会的使之从地图或其他知名收藏类派生的,因为你是如何存储这些信息的语义可能会在将来改变。

除了实现其联系在一起客户及其连接一个类,这个类里面使用适当的集合类(即你在自由以后改变而不影响接口和你的代码的其余部分)

您的客户/连接管理器类是比简单的容器更。它可以存储的元数据(在这种关系成立例如当)。它可以在给定的客户信息连接进行搜索(如果需要)。它可以处理重复你如何要求,而不是底层集合类是如何处理他们等等等,你可以在调试/日志/性能监控容易插槽,方便地了解发生了什么事情。

我认为您还应该考虑如何使用集合以及如何获取数据:

  • 如果它们是要显示在页面上的简单结果集(例如),那么使用标准集合似乎是合理的 - 然后您可以使用大量标准库来操作它们。
  • 另一方面,如果它们是可变的并且需要保留任何更改(例如),那么将它们封装在您自己的类中可能会更好(然后可以将更改写入数据库等)。

您如何获取并保存您的数据?如果它存储在数据库中,那么也许您可以使用 SQL 按客户和/或服务和/或月份选择 LastConnections,而不必自己维护数据结构(并且只返回简单的列表或连接映射或连接计数)。或者您可能不想为每个请求运行查询,因此需要将整个数据结构保留在内存中。

不过,封装通常是一件好事,特别是因为它可以帮助您遵守 德墨忒耳定律 - 也许您可以将对集合执行的一些操作推回 AllConnections 类(实际上是一个 DAO)。这通常可以帮助单元测试。

另外,考虑到您只想添加一个简单的辅助方法,为什么在这里扩展 HashMap 被认为是邪恶的呢?在 AllConnections 的代码中,AllConnections 的行为方式始终与 HashMap 相同 - 它是多态可替换的。当然,您可能会锁定自己使用 HashMap(而不是 TreeMap 等),但这可能并不重要,因为它具有与 Map 相同的公共方法。然而,您是否真的想要这样做确实取决于您打算如何使用集合 - 我只是不认为您应该自动折扣实现继承 总是 不好(通常都是这样!)

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

为什么不使用custId+"#"+srvurl如在简单Map<String, LastConnection>一个键?

或者使用元组或Pair类作为包含两个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