软件设计:课程太多了?

时间:2016-05-10 22:31:57

标签: c++ oop design-patterns

我在软件设计方面是一个非专业人士。我正面临一个"问题"这可能是通过我想要讲述的一些众所周知的技术/成语/模式来解决的。

我有一个抽象基类,基本上定义了一个纯虚拟成员函数,而其他几乎没有。然后我有几个派生自这个的类并覆盖所述虚函数。我现在有六个这样的课程,而且这个数字正在增长。这些类只有几个数据成员(很少,就像几个双精度或加上一个函数指针),它们的区别主要在于它们执行非常短的计算。我想知道这是否表明设计不好,并且更好地以其他方式处理。

如果合适,有人可以指出我应该知道的相关设计模式或习语。感谢。

修改

为了澄清事情,抽象基类没有任何数据成员。并非所有派生类都有数据成员。我正在做的是将积分的坐标转换作为类。给定的转换只需要几个参数,有时需要用户提供的功能。

5 个答案:

答案 0 :(得分:3)

一个带有一个虚函数的抽象基类听起来几乎就像一个包含lambda的std::function<>

例如:

#include <functional>
#include <vector>
#include <iostream>

int main()
{
    using op = std::function<int()>;

    int x = 7;
    int y = 5;
    auto a = [x, y]() -> int { return x + y; };
    auto b = [x, y]() -> int { return x - y; };

    auto ops = std::vector<op> { a, b };
    for (const auto& o : ops)
    {
        std::cout << o() << std::endl;
    }
}

最后,lambda只是编写一个类的简写形式,它捕获(复制)一些对象或对象的引用并公开一个调用操作符。

std :: function是这类的多态适配器。

使用lambdas可以节省一些打字。它是否增加或减少代码的语义表达(这可能更重要)是另一回事。

答案 1 :(得分:2)

如果你的抽象基类没有任何数据成员(如果它有一个纯虚方法似乎不应该),那么确实有一个更好的模式。假设我们有这个代码:

struct AbstractBase {
  virtual double calc(double) = 0;
  virtual ~AbstractBase() = default
}

现在,你必须继承这个,以便在其他地方动态使用:

struct Derived : public AbstractBase { ... }

void BaseUser(AbstractBase& ab) { ... };

一个耦合度较低的解决方案就是将您的类编写为函数对象并使用std::function

struct Derived {
  double operator()(double x) { ... };
}

void User(std::function<double(double)> f);

User(Derived{}); // Calls user with Derived routine.

这也有其他优点,例如,如果你的某些派生类实际上不需要状态,那么你可以将它们作为普通函数编写,并在std::functions中传递它们。另一个好处是你现在也可以内联编写短函数,因为lambda是一个函数对象:

User([] (double x) { return 2*x; });

如果你需要更多的精确控制而不是一个虚拟函数调用的抽象基类,那么当界面中只有一个函数时,我至少会考虑查看函数对象。 / p>

我不会担心你必须拥有的派生对象的数量。

答案 2 :(得分:1)

有一种说法:干。 D R epeat Y 我们自己。除了覆盖纯虚方法之外,如果存在任何其他形式的重复代码,那么这可能是需要修订的标志。如果你有很多类,每个类的功能都是独一无二的,那就没关系。

答案 3 :(得分:1)

如果没有看到一个例子,很难完全评论。一般来说,你有很多类,每个类只执行一小部分(一组)操作,这并不一定表明设计不好。您应该尽可能多地尝试使用DRY(不要重复自己)和SOLID(请参阅this wikipedia article)原则来构建类。

答案 4 :(得分:0)

如果可以编写操作,那么您应该尝试编写对象以组成操作。一个班级应该只做一件事,所以你不一定有问题。