簡體   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