什么是一个好的设计模式来容纳一个不可互换的对象池?

时间:2014-04-30 10:48:34

标签: design-patterns singleton pool

我正在为这种情况寻找一个好的设计模式:

我有一堆硬件设备,每个设备都由一个C ++库中的类表示(让我们称之为 Device )。使用该库的计算机会为每个设备打开 UDP套接字(它们由我的网络中的IP标识)。库和设备之间的通信是通过 JSON消息进行的。因此,库通过套接字发送和接收JSON对象。

库所做的第一件事就是发现设备数量,要求包含该信息的JSON对象(基本上是每个设备的IP)。之后,使用所有 Device 对象构建一个向量。

这可以被视为对象池,因为最后,我有一组 Device 对象,每个对象封装一个网络连接。但他们不可互换。在数据库连接池中,我可以选择一个对象并使用它来连接我的数据库。但是,如果我需要向特定设备发送消息,我需要设备对象。不是另一个

该类的原始创建者将其建模为包含向量的 Singleton 。因为我们只想要一个入口点来访问 Device 对象的向量。但我认为这是can cause problems

有没有更好的方法来模拟这个类?

2 个答案:

答案 0 :(得分:2)

似乎您需要的是Abstract Factory Pattern

这个想法是你要求工厂提供一个将所有相关组件连接在一起的对象,这样你就不会弄错它们。这通常用于UI设计(例如,确保您不会意外地将Windows按钮与Mac Style组合框混合),但直接适用于您。

所以,在Java语法中(因为我多年没有编写C ++)

// this is where you do the discovery you mentioned.
DeviceManager manager = DeviceManager.getInstance(); 

Device d = manager.getDevice("some-id");
// device c, d will be from the same set here because a reference to them 
// can only come through this manager
Device c = manager.getDevice("c-id");

如果您需要隐藏级联消息传递功能,Composite Pattern也非常方便。

答案 1 :(得分:1)

我不会将此集合称为pool。拥有一个对象池的目的是减少同一类型的多个实例的实例化成本,允许客户端返回"使用后,资源返回池中。您的设备不能透明地互换,并且集合点与资源使用完全无关。

我想到了两种方法:

  1. 您可以使用map使用其唯一键(例如Device)快速获取某个std::map<std::string, Device>,但您可能应该更好地了解要使用的内容键而不是普通字符串),类似于:

    // find the right device instance
    string deviceInfo = "some-unique-key";
    Device device = devicesMap.find(deviceInfo)->second;
    
    // send the data
    string json = serialize(dataObject);
    device.send(json);
    

    另一方面,如果某些设备的协议可能不同,您可能希望将实际(反)序列化委派给Device本身:

    // find the right device instance
    string deviceInfo = "some-unique-key";
    Device device = devicesMap.find(deviceInfo)->second;
    
    // send the object, Device class will know how to serialize it
    device.send(dataObject);
    
  2. 另一个有趣的选择是将消息发送到所有Device实例,并让他们决定消息是否与他们相关(基于您认为合适的任何内容)。这种方法允许多个设备可以发送相同的消息,如果他们喜欢它,或者只是在没有发送任何内容的情况下被通知发生了什么的情况:

    // notify all devices that we have a message
    for (auto &device : devicesVector) {
    
        // you are only notifying the device.
        // each instance should decide whether or not to
        // pass the message forward (based on its contents),
        // and how to serialize it
    
        device.notify(dataObject);
    }
    
  3. 您当前的实现是Singleton的事实是一个单独的问题。 Singleton是一种创造性的模式,与对象的生命周期相关,通常仅用于避免传递依赖性。它稍微简化了ctor签名,但也可能涉及一些懒惰,特别是考虑到你使单元测试更难一点的事实。

    正确的dependency injection patterns会要求您明确地将此服务传递给所有使用者(通常是彻底的构造函数注入),这会导致更少的耦合,从而使单元测试更容易。这并不意味着您需要重构整个代码以使用DI容器,而只是简单地传递&#34; thingy&#34;它通过构造函数处理与调用者的通信。