对于可以从不同来源接收数据的单个对象,我需要啥设计模式?

Posted

技术标签:

【中文标题】对于可以从不同来源接收数据的单个对象,我需要啥设计模式?【英文标题】:What design pattern do I need for a single object which can receive data from different sources?对于可以从不同来源接收数据的单个对象,我需要什么设计模式? 【发布时间】:2018-08-22 16:09:30 【问题描述】:

我正在尝试在 Swift 中创建一些代码来启用以下功能。有一个类(称为 Datastore)是代码的主要接口——这是大多数 API 用户大部分时间都会处理的。

这个 Datastore 类很灵活。您可以将它与来自文本文件、蓝牙数据或通过 WiFi 传入的数据等数据一起使用。我称这些数据提供者为。因此,例如,您可以有一个 BTProvider 类,该类将接收蓝牙数据并在数据到达时将其发送到数据存储区。一个 Datastore 永远不需要从多个数据提供者那里获取数据。

哪些设计模式或语言工具可以帮助我实现这一目标?

我考虑过使用协议,但感觉是倒退了——协议定义了对象可以响应的方法——但在这种情况下,这将是 Datastore 对象——其中只有一个。在我的脑海里,我觉得我想要一个反向协议——我可以保证“这个对象/调用/在另一个对象上的这些方法”。然后所有的提供者都可以实现这一点,Datastore 可以有一个方法“setProvider: ProviderOfData”,其中数据的提供者是反向协议的名称。

如果我可以从数据存储区轮询提供程序,这会容易得多(然后他们可以实现一个协议来定义像“getMostRecentData”这样的方法,但由于它的性质(从 WiFi、蓝牙等接收异步数据) .) 这是不可能的,而且感觉不优雅——不过如果你有想法,我愿意接受!

这似乎不是第一次这样做,所以我对它通常是如何完成的很感兴趣,所以我不必重新发明***。

【问题讨论】:

【参考方案1】:

我可以保证“这个对象/调用/在另一个对象上的这些方法”。

您似乎需要的是 Delegate-Pattern

你可以有一个DataStore(Swift 是驼峰式的),这个类可以实现多个委托协议。示例:

class DataStore 

    // logic of the DataStore


您说您的应用程序主要是一个类(DataStore),所以我猜您有人从中初始化您的提供程序。我建议:

// Provider Factory
extension DataStore 
    func makeBluetoothProvider() 
        let btProvider = BTProvider()
        btProvider.delegate = self
    
    // creation of other providers, or you can create them all at once.

不是重要的部分,DataStore 是您的提供者的代表,这样,当他们检索数据时,他们可以调用DataStore。我会有这样的协议:

protocol ProviderDelegate: class 
    func provider(_ provider: Provider, didFinishReceiving data: Data)


extension DataStore: ProviderDelegate 
    func provider(_ provider: Provider, didFinishReceiving data: Data) 
         // read data and do something with it...display it, save it, etc.
    

Provider 将是所有提供者的通用类,可能带有网络请求或类似的基本数据。一个例子是:

class Provider 
    var delegate: ProviderDelegate
    var data: Data


class BTProvider: Provider 
    // logic only for bluetooth provider

根据您的提供者的行为方式不同,您可以为每个提供一个委托协议和一个 DataStore 的扩展来实现这些协议中的每一个。只有当行为彼此差异太大时才会这样做,我不这么认为。

更新地址评论:协议可以提供代码

协议可以提供代码,我举个例子:

protocol Provider 
    weak var delegate: ProviderDelegate  get set 
    func fetchData(with url: URL)
    func processData(data: Data)


extension Provider 
    func processData(data: Data) 
        // do some processing that all providers have to do equally
        // probably also call delegate to tell DataStore it is ready
    

您的提供者类将实现该方法,并且可以选择实现一个新的processData 或仅使用默认。如果它实现了它,则无需调用override,您将无法再访问协议方法。您的提供者可能如下所示:

class BTProvider: Provider 

    weak var delegate: Provider?

    func fetchData(with url: URL) 
        // do some logic to fetch data for this provider
        processData(data: whateverWasFetched)
    

【讨论】:

这对您有帮助吗?你有问题吗? 这看起来很棒 - 谢谢。我只是想知道您是否认为“Provider”(基类)应该是一个协议?对我来说,这是有道理的,因为“Provider”的实例没有任何意义——它只在实例化子类的上下文中才有意义。我想这取决于每个 Provider 做了多少共享工作,因为协议不能提供代码,对吧? 如你所说,这取决于他们有多少共同点。但是协议 cat 提供代码。看看更新。 好的,很好。我想在这种情况下我会让 Provider 成为一个协议。非常感谢您的帮助!

以上是关于对于可以从不同来源接收数据的单个对象,我需要啥设计模式?的主要内容,如果未能解决你的问题,请参考以下文章

如何在单个 TCP 数据包中从不同文件中分离数据?

Yammer REST API - 如何从不同来源 (CORS) 获取数据?

访问从不同来源加载的 iframe 的内容

如何从不同来源的 Chrome 扩展程序提供文件?

从不同文件发送数据的简单 perl 程序

从不同来源的跨平台音频导入