如何为对象提供不同的接口(最佳)

问题描述 投票:0回答:2

我需要一种方法来从单个对象提供不同的接口。 例如。用户1应该能够调用Foo::bar()并且用户2应该能够调用Foo::baz()但是用户不能调用Foo::baz()并且用户2分别不能调用Foo::bar()

我确实设法做到了这一点,但我认为这不是最佳选择。

class A
{
    public:
    virtual void bar() = 0;
    virtual ~A() = 0;
};

class B
{
    public:
    virtual void baz() = 0;
    virtual ~B() = 0;
};

class Foo : public A, public B
{
    public:
    Foo() = default;
    void baz() override;
    void bar() override;

};

class Factory
{
    public:
    Factory()
    {
        foo = std::make_shared<Foo>();
    }
    std::shared_ptr<A> getUserOne()
    {
        return foo;
    }

    std::shared_ptr<B> getUserTwo()
    {
        return foo;
    }

    private:
    std::shared_ptr<Foo> foo;
};

有没有更好的方法来实现这一目标。也许使用包装器对象。我真的不需要用newstd::make_shared)分配这个foo对象我甚至不愿意,但我不能使用原始指针和智能指针给出不必要的开销和系统调用。

编辑:我会试着举个例子。 有一辆车。用户一是驱动程序。他可以驾驶方向盘,加速或使用休息时间。用户2是乘客,他可以控制无线电。我不希望乘客能够使用休息时间或司机能够使用收音机。 此外,他们都在车内,因此用户1的动作将对用户2产生影响,反之亦然。

c++ smart-pointers multiple-instances
2个回答
1
投票

您实际需要的是两个对象之间的共享数据。继承对此不是一个很好的选择,因为不仅你不需要is A关系,而且你明确地想要避免它。因此,组合是你的答案,特别是因为你有一个工厂:

class Data
{
public:
    void bar();
    void baz();
};

然后你将使用组合而不是继承:

class A
{
public:
    A(Base *base) : mBase(base) {}

    void bar() { mBase->bar(); }

private:
    Base *mBase = nullptr;
};

//class B would be the same only doing baz()

最后Factory

class Factory
{
public:
    A *getUserOne() { return &mA; }
    B *getUserTwo() { return &mB; }

private:
    Base mBase;
    A mA(&mBase);
    B mB(&mBase);
};

关于这个解决方案的几点。虽然它不在堆上分配,但只要有用户,就需要保持Factory活着。因此,在OP中使用std::shared_ptr可能是一个明智的想法。 :-)但是当然还有原子引用计数的成本。

其次AB无关。这是设计的,与原始解决方案不同,不允许在dynamic_castA之间使用B

最后,实施将取决于您。你可以在Data拥有一切,并且AB只是称之为(如上所述),但你也可以将Data变成只包含你的数据的struct,并分别在AB中实现你的方法。后者更像是“面向数据”的节目,这些节目现在很受欢迎,而不是更传统的“面向对象”,这是我选择展示的。


0
投票

您可以单独声明数据

struct Data
{
    /* member variables */
};

有一个能够操纵所述数据的接口类将保护所有成员

class Interface
{
protected:
    Interface(Data &data) : m_data{data} {}

    void bar() { /* implementation */ }
    void baz() { /* implementation */ }

    Data &m_data;
};

派生类别是公共特定成员

class A : private Interface
{
public:
    A(Data &data) : Interface{data} {}
    using Interface::bar;
};

class B : private Interface
{
public:
    B(Data &data) : Interface{data} {}
    using Interface::baz;
};

这样,您还可以让用户能够重叠访问某些功能,而无需多次实现。

class Admin : private Interface
{
public:
    Admin(Data &data) : Interface{data} {}
    using Interface::bar;
    using Interface::baz;
};

当然,根据您使用数据的方式,您可能需要指针或共享指针,可能会在多个线程的访问之间添加一些同步。

使用此模型的示例代码:

void test()
{
    Data d{};

    auto a = A{d};
    a.bar();
    // a.baz is protected so illegal to call here

    auto b = B{d};
    b.baz();
    // b.bar is protected so illegal to call here

    auto admin = Admin{d};
    admin.bar();
    admin.baz();
}

在我看来,无论您有多少用户类型,您只有一组数据和一个数据操作实现,这对我来说似乎很有效。

© www.soinside.com 2019 - 2024. All rights reserved.