首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在C++中使用模板而不是桥接模式

在C++中使用模板而不是桥接模式
EN

Stack Overflow用户
提问于 2017-08-22 03:52:11
回答 5查看 838关注 1票数 6

我有三种类型的数据链路: RS485,I2C和蓝牙。每条数据链路都有连接、读写数据等功能。在PC软件上,我必须实现应用程序/协议层才能与设备协同工作。在我之前关于OOP的问题中,我得到了使用Bridge模式或工厂方法的答案,但我认为这可以做得更好。我会问,如果不是更好地使用模板来完成这项任务。下面是我想要如何使用它的简单示例:

代码语言:javascript
运行
复制
// Low level datalink class
class RS485
{
public:
    void send(const char *data) {
        // datalink function to send data using RS485
        printf("RS485: %s \n", data);
    }
};

class I2C
{
public:
    void send(const char *data) {
        // datalink function to send data using I2C
        printf("I2C: %s \n", data);
    }
};

class BT
{
public:
    void send(const char *data) {
        // datalink function to send data using Bluetooth
        printf("BT %s \n", data);
    }
};

// Protocol class
template<typename Comm>
class MODBUS
{
public:
    MODBUS(Comm *c) { _c = c; }

    void send(const char *data) {
        printf("MODBUS\n");
        _c->send(data);
    }
private:
    Comm *_c;
};

// Protocol class
template<typename Comm>
class TCP
{
public:
    TCP(Comm *c) { _c = c; }

    void send(const char *data) {
        printf("TCP\n");
        _c->send(data);
    }
private:
    Comm *_c;
};

int main() {
    // Modbus over I2C
    I2C *i2c = new I2C();
    MODBUS<I2C> *mb_i2c = new MODBUS<I2C>(i2c);
    mb_i2c->send("Data ...");

    // Modbus over RS485
    RS485 *rs = new RS485();
    MODBUS<RS485> *mb_rs = new MODBUS<RS485>(rs);
    mb_rs->send("Data ...");

    // Tcp over Modbus over RS485
    TCP< MODBUS<RS485> > *tcp_modbus_rs = new TCP< MODBUS<RS485> >(mb_rs);
    tcp_modbus_rs->send("Data ...");

    return 0;
}
EN

回答 5

Stack Overflow用户

发布于 2017-08-22 04:07:33

作为一个经验法则--不要优化(现在)。如果对send的虚拟调用不是瓶颈,为什么还要费心用包含更多样板代码的模板替换接口呢?

从您的代码看,似乎没有必要追求任何模式-只需对这些类进行硬编码,您就可以更快地完成工作。

编辑:如果你真的想把协议链接在一起,这里有一个功能强大的方法:

代码语言:javascript
运行
复制
struct TCP
{
    void onsend(const char* data) {}
};

struct MODBUS
{
    void onsend(const char* data) {}
};

struct RS485
{
    void onsend(const char* data) {}
};

template<typename F, typename Prot, typename... TProtocols>
auto channel(F&& f, Prot&& prot, TProtocols&&... protocols)
{
    return [&](const char* data)
    {
        f(prot, data);
        channel(f, protocols...)(data);
    };
}

template<typename F, typename Prot>
auto channel(F&& f, Prot&& prot)
{
    return [&](const char* data)
    {
        f(prot, data);
    };
}

int main()
{
    TCP tcp;
    MODBUS modbus;
    RS485 rs;

    auto chan = channel([](auto&& protocol, const char* data)
    {
        protocol.onsend(data);
    }, 
    tcp, modbus, rs);

    const char msg[] = "asdfasdf";
    chan(msg);
}

基本上,你希望对象一个接一个地接收消息,谁说它们的类型需要相关呢?

票数 1
EN

Stack Overflow用户

发布于 2017-08-22 04:07:45

您可以使用mixins-from-below来减少一些样板文件。它与您的示例没有太大的不同,但是您有更少的代码,并且没有指针。你仍然可以(让我说)从协议的各个部分组成你的协议。

以下是修改后的代码片段,以使用它们:

代码语言:javascript
运行
复制
#include<cstdio>

// Low level datalink class
struct RS485 {
    void send(const char *data) {
        // datalink function to send data using RS485
        printf("RS485: %s \n", data);
    }
};

struct I2C {
    void send(const char *data) {
        // datalink function to send data using I2C
        printf("I2C: %s \n", data);
    }
};

struct BT {
    void send(const char *data) {
        // datalink function to send data using Bluetooth
        printf("BT %s \n", data);
    }
};

// Protocol class
template<typename Comm>
struct MODBUS: private Comm {
    void send(const char *data) {
        printf("MODBUS\n");
        Comm::send(data);
    }
};

// Protocol class
template<typename Comm>
struct TCP: private Comm {
    void send(const char *data) {
        printf("TCP\n");
        Comm::send(data);
    }
};

int main() {
    // Modbus over I2C
    MODBUS<I2C> mb_i2c{};
    mb_i2c.send("Data ...");

    // Modbus over RS485
    MODBUS<RS485> mb_rs{};
    mb_rs.send("Data ...");

    // Tcp over Modbus over RS485
    TCP< MODBUS<RS485> > tcp_modbus_rs{};
    tcp_modbus_rs.send("Data ...");
}

如果您的部件有接受不同参数列表的构造函数,您可以使用转发引用和模板化构造函数来满足要求。

举个例子:

代码语言:javascript
运行
复制
// Protocol class
template<typename Comm>
struct MODBUS: private Comm {
    template<typename... T>
    MODBUS(T&&... t): Comm{std::forward<T>(t)...} {}

    void send(const char *data) {
        printf("MODBUS\n");
        Comm::send(data);
    }
};

下面是以这种方式修改的完整示例:

代码语言:javascript
运行
复制
#include<cstdio>
#include<utility>

// Low level datalink class
struct RS485 {
    RS485(int) {}

    void send(const char *data) {
        // datalink function to send data using RS485
        printf("RS485: %s \n", data);
    }
};

struct I2C {
    I2C(char, double) {}

    void send(const char *data) {
        // datalink function to send data using I2C
        printf("I2C: %s \n", data);
    }
};

struct BT {
    void send(const char *data) {
        // datalink function to send data using Bluetooth
        printf("BT %s \n", data);
    }
};

// Protocol class
template<typename Comm>
struct MODBUS: private Comm {
    template<typename... T>
    MODBUS(T&&... t): Comm{std::forward<T>(t)...} {}

    void send(const char *data) {
        printf("MODBUS\n");
        Comm::send(data);
    }
};

// Protocol class
template<typename Comm>
struct TCP: private Comm {
    template<typename... T>
    TCP(T&&... t): Comm{std::forward<T>(t)...} {}

    void send(const char *data) {
        printf("TCP\n");
        Comm::send(data);
    }
};

int main() {
    // Modbus over I2C
    MODBUS<I2C> mb_i2c{'c', .3};
    mb_i2c.send("Data ...");

    // Modbus over RS485
    MODBUS<RS485> mb_rs{42};
    mb_rs.send("Data ...");

    // Tcp over Modbus over RS485
    TCP< MODBUS<RS485> > tcp_modbus_rs{23};
    tcp_modbus_rs.send("Data ...");
}
票数 1
EN

Stack Overflow用户

发布于 2017-08-22 04:39:51

在这种情况下,模板解决方案似乎不是一个好主意。

你真的希望对象的类型依赖于什么是“实现的”吗?

使用虚函数似乎是正确的方法(将指向较低级别通道的指针作为构造函数中的基类指针传递)。

虚函数方法需要使用指针并仔细处理生存期,但标准解决方案是使用智能指针。

代码语言:javascript
运行
复制
#include <stdio.h>
#include <memory>

struct DataLink {
    virtual void send(const char *data) = 0;
    virtual ~DataLink(){}
};

typedef std::shared_ptr<DataLink> DLPtr;

struct RS485 : DataLink {
    void send(const char *data) { printf("RS485: %s \n", data);}
};

struct I2C : DataLink {
    void send(const char *data) { printf("I2C: %s \n", data); }
};

struct BT : DataLink {
    void send(const char *data) { printf("BT %s \n", data); }
};

struct MODBUS : DataLink {
    DLPtr channel;
    MODBUS(const DLPtr& channel) : channel(channel) {}
    void send(const char *data) {
        printf("MODBUS\n");
        channel->send(data);
    }
};

struct TCP : DataLink {
    DLPtr channel;
    TCP(const DLPtr& channel) : channel(channel) {}
    void send(const char *data) {
        printf("TCP\n");
        channel->send(data);
    }
};

int main() {
    DLPtr dl1(new MODBUS(DLPtr(new I2C)));
    dl1->send("data ...");
    DLPtr dl2(new MODBUS(DLPtr(new RS485)));
    dl2->send("data ...");
    DLPtr dl3(new TCP(DLPtr(new MODBUS(DLPtr(new RS485)))));
    dl3->send("data ...");
    return 0;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45804589

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档