使用 C++ 中现有的 类 进行代码重构
Code refactoring with existing classes in C++
我用 C++ 编写代码,由于该语言中没有 interface 关键字,因此我将在此处将接口用作概念(契约)。
假设你有一个接口 IBase,它已经被几十个 classes 实现了。现在您需要在该接口 IBase 中添加另一个方法。
以最小的方式进行更改以解决在所有实施 classes 中重写该方法的问题的方法是什么?
一种方法是在 Ibase class 中添加具有默认实现的新方法,并让需要它的派生 class 覆盖它。
在上面的解决方案中,我觉得我在两个地方出错了,通过触摸界面打破了开闭原则,也通过告诉用户你也可以调用另一个方法来打破契约。
另一件让我印象深刻的事情是,我在基础上添加了一个方法,只有一个派生的 class 覆盖了它,这基本上意味着其他 class 不需要那个方法。
所以这让我想到了另一个解决方案,其中需要此方法的 class 将从提供此功能的另一个 class 继承或使用组合来使用另一个 [=36] 的功能=].
通过上述解决方案,我遇到了另一个问题,即客户端如何通过 Ibase 接口访问派生的 class 的新功能。 C++ 中的动态调度仅在函数存在于基 class.
中时才有效
有人可以帮忙吗!
更新
我只是根据下面的评论对我的理解进行了编码,但现在客户端代码看起来很乱,它必须知道使用哪个接口来实现额外的功能。我们应该使用工厂/抽象工厂抽象下面的代码吗?
#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;
}
很难真正知道什么适合您的情况,因为您显然有一个工作系统,它可能会或可能不会从我们可能建议的任何事情中受益。
不过,我提供了一个示例,说明您如何可以 管理具有单独 and/or 重叠职责的多个子类型。这种方法是让一个 master 容器持有 all 对象的所有权,使用 std::unique_ptr
确保它们都被删除,我们有没有内存泄漏。
在那个 master 容器的 addition 中,我们为不同的 views 提供了单独的容器。每个 view 都包含对那些具有特定责任但不与其他类型共享的元素的引用(原始指针)。
也许对你的情况有用,也许没用:
#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 和新接口的组合来创建新的而不影响以前的 类。
我用 C++ 编写代码,由于该语言中没有 interface 关键字,因此我将在此处将接口用作概念(契约)。
假设你有一个接口 IBase,它已经被几十个 classes 实现了。现在您需要在该接口 IBase 中添加另一个方法。
以最小的方式进行更改以解决在所有实施 classes 中重写该方法的问题的方法是什么?
一种方法是在 Ibase class 中添加具有默认实现的新方法,并让需要它的派生 class 覆盖它。
在上面的解决方案中,我觉得我在两个地方出错了,通过触摸界面打破了开闭原则,也通过告诉用户你也可以调用另一个方法来打破契约。
另一件让我印象深刻的事情是,我在基础上添加了一个方法,只有一个派生的 class 覆盖了它,这基本上意味着其他 class 不需要那个方法。
所以这让我想到了另一个解决方案,其中需要此方法的 class 将从提供此功能的另一个 class 继承或使用组合来使用另一个 [=36] 的功能=].
通过上述解决方案,我遇到了另一个问题,即客户端如何通过 Ibase 接口访问派生的 class 的新功能。 C++ 中的动态调度仅在函数存在于基 class.
中时才有效有人可以帮忙吗!
更新
我只是根据下面的评论对我的理解进行了编码,但现在客户端代码看起来很乱,它必须知道使用哪个接口来实现额外的功能。我们应该使用工厂/抽象工厂抽象下面的代码吗?
#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;
}
很难真正知道什么适合您的情况,因为您显然有一个工作系统,它可能会或可能不会从我们可能建议的任何事情中受益。
不过,我提供了一个示例,说明您如何可以 管理具有单独 and/or 重叠职责的多个子类型。这种方法是让一个 master 容器持有 all 对象的所有权,使用 std::unique_ptr
确保它们都被删除,我们有没有内存泄漏。
在那个 master 容器的 addition 中,我们为不同的 views 提供了单独的容器。每个 view 都包含对那些具有特定责任但不与其他类型共享的元素的引用(原始指针)。
也许对你的情况有用,也许没用:
#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 和新接口的组合来创建新的而不影响以前的 类。