繁体   English   中英

使用C ++中的现有类进行代码重构

[英]Code refactoring with existing classes in C++

我用C ++编写代码,由于接口关键字不在语言中,我将在这里使用接口作为概念(合同)。

假设你有一个接口说IBase,它已被几十个类实现。 现在,您需要在该接口IBase中添加另一个方法。

以最小的方式进行更改以解决在所有实现类中重写该方法的问题的方法是什么?

一种方法是在Ibase类中添加带有默认实现的新方法,并让需要它的派生类覆盖它。

在上面的解决方案中,我觉得我在两个地方出错了,通过触摸界面打破了开放的封闭原则,并通过告诉用户你也可以调用另一种方法来打破合同。

在这里让我感到震惊的另一件事是,我在基础上添加了一个方法,只有一个派生类覆盖它,这基本上意味着其他类不需要该方法。

这样我就可以使用另一个解决方案,其中需要此方法的类将继承自另一个提供此功能的类或使用组合来使用另一个类的功能。

通过上面的解决方案我遇到了另一个问题,客户端如何通过Ibase接口访问派生类的新功能。 只有函数存在于基类中时,C ++中的动态调度才有效。

有人可以帮忙!

UPDATE

我只是根据下面的评论编写了我的理解,但现在客户端代码看起来很乱,它必须知道哪个接口用于额外的功能。 我们应该使用工厂/抽象工厂抽象下面的代码吗?

#include <iostream>

using namespace std;


class IBase {
    public:
     virtual void test() = 0; 
};

class INewInterface {
    public:
     virtual void newMethod() = 0; 
};

class Derived : public IBase {
    public:
    virtual void test () {
        cout<< " Derived  " << endl;
    }
};

class DerivedSecond: public IBase, public INewInterface {
    public:
    virtual void test() {
        cout<< " Derived Second " << endl;
    }

    void newMethod( ) {
        cout<< " newMethod " << endl;
    }
};

int main( int argc, char ** argv ) {

    // Client code
    //Client needs to cast to two different interfaces to get access to the new functionality.
    // Probably should use a factory here 
    INewInterface * pNewInterfacePtr = dynamic_cast< INewInterface * > ( new DerivedSecond );
    IBase *         pIbasePtr        = dynamic_cast< IBase * > ( new DerivedSecond );

    pIbasePtr->test();
    pNewInterfacePtr->newMethod();
    return 0;
}

很难真正了解什么适合您的情况,因为您显然拥有一个可能会或可能不会从我们建议的任何事情中受益的工作系统。

不过,我产生了一个如何管理与单独和/或职责重叠多个亚型的例子。 这种方法是让一个容器使用std::unique_ptr保存所有对象的所有权,以确保它们都被删除,并且我们没有内存泄漏。

除了 容器之外 ,我们还有不同视图的独立容器。 每个视图都包含对那些具有不与其他类型共享的特定职责的元素的引用(原始指针)。

也许它可能在你的情况下有用,也许不是:

#include <vector>
#include <memory>
#include <iostream>

class Role
{
public:
    virtual ~Role() {}
};

class RoleOne
: public virtual Role
{
public:
    virtual void do_role_one_stuff() = 0;
};

class RoleTwo
: public virtual Role
{
public:
    virtual void do_role_two_stuff() = 0;
};

class ItemA
: public RoleOne
{
public:
    void do_role_one_stuff() override { std::cout << "Item A in Role One\n"; }
};

class ItemB
: public RoleOne
, public RoleTwo
{
public:
    void do_role_one_stuff() override { std::cout << "Item B in Role One\n"; }
    void do_role_two_stuff() override { std::cout << "Item B in Role Two\n"; }
};

class ItemC
: public RoleTwo
{
public:
    void do_role_two_stuff() override { std::cout << "Item C in Role Two\n"; }
};

class Resources
{
    // unique_ptr ensures deletion (no memory leaks)
    std::vector<std::unique_ptr<Role>> all; // owning container

    // raw 'access' pointers share access (no need to share ownership)
    std::vector<RoleOne*> ones; // alternate 'view' (no ownership)
    std::vector<RoleTwo*> twos; // alternate 'view' (no ownership)

public:
    void add_item(Role* item)
    {
        // manage ALL items life-spans here
        all.emplace_back(item);

        // add one-centric items to the one-centric view
        if(auto one = dynamic_cast<RoleOne*>(item))
            ones.emplace_back(one);

        // add two-centric items to the two-centric view
        if(auto two = dynamic_cast<RoleTwo*>(item))
            twos.emplace_back(two);
    }

    void do_business()
    {
        // ItemA and ItemB types do this kind of business
        std::cout << "\nDoing role one business:\n";
        for(auto role: ones)
            role->do_role_one_stuff();

        // ItemB and ItemC types do this kind of business
        std::cout << "\nDoing role two business:\n";
        for(auto role: twos)
            role->do_role_two_stuff();
    }
};

int main()
{
    Resources res;

    res.add_item(new ItemA);
    res.add_item(new ItemB);
    res.add_item(new ItemC);
    res.add_item(new ItemB);
    res.add_item(new ItemA);
    res.add_item(new ItemC);

    res.do_business();
}

输出:

Doing role one business:
Item A in Role One
Item B in Role One
Item B in Role One
Item A in Role One

Doing role two business:
Item B in Role Two
Item C in Role Two
Item B in Role Two
Item C in Role Two

请记住,原则不是规则。 有时你会发现你必须在真正的世界中打破一些原则,如果你明白自己在做什么,这将是一个很好的决定。 然后,在IBase中创建新的虚拟方法的选项可能是您的解决方案。

如果你不想打破实际的界面,我会使用组合和委托。 但我不知道你的问题。 也许我的解决方案不适合你的情况。

class IBase {
public:
    virtual void test() = 0;
};
class INewIfc {
protected:
    IBase* ifc;
public:
    INewIfc(IBase* _ifc) : ifc(_ifc) {}
    ~INewIfc() {}
    virtual void newMethod() = 0;
    IBase* getIfc() {return ifc;}
}

然后,您从IBase(您拥有的)创建具体类,或使用IBase的组合和新接口创建新的接口,而不会影响以前的类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM