Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
roth_stephan_clean_c20_sustainable_software_development_patt.pdf
Скачиваний:
29
Добавлен:
27.03.2023
Размер:
7.26 Mб
Скачать

Chapter 6 Modularization

bool isRunning; unsigned int pressure;

static const unsigned int NORMAL_FUEL_PRESSURE { 120 };

};

Of course, not all getters are inherently bad. Sometimes it is necessary to retrieve information from an object, for example, if this information should be displayed on a graphical user interface.

Avoid Static Class Members

I can well imagine that many readers are wondering now: what is wrong with static member variables and static member functions?

Well, perhaps you still remember the God Class anti-pattern described in the earlier section on small classes. There I’ve described that utility classes typically tend to become such huge “God Classes.” In addition, these utility classes usually also consist of many static member functions, often even without exception. The quiet comprehensible justification for this is: why should I force users of the utility class to create an instance of it? Because such classes offer a colorful assortment of different functions for different purposes, which is a sign of weak cohesion by the way, I have created a special pattern name for these cluttered things: the Junk Shop anti-pattern. According to the online encyclopedia Wikipedia, a junk shop is a retail outlet similar to a thrift store that offers a broad assortment of mostly used goods at cheap prices. See Listings 6-33 and 6-34.

Listing 6-33.  Excerpt from Some Utility Class

class JunkShop { public:

// ...many public utility functions...

static int oneOfManyUtilityFunctions(int param); // ...more public utility functions...

};

279

Chapter 6 Modularization

Listing 6-34.  Another Class That Uses the Utility Class

#include "JunkShop.h"

class Client {

// ...

void doSomething() {

// ...

y = JunkShop::oneOfManyUtilityFunctions(x);

// ...

}

};

The first problem is that your code becomes hard-wired with all those static helper functions in these “junk shops.” As it can easily be seen from the previous example, such static functions from utility classes are used somewhere in the implementation of another software module. Hence, there is no easy way to replace this function call with something else. But in unit testing (see Chapter 2), this is exactly what you want to do.

Furthermore, static member functions foster a procedural programming style. Using them in conjunction with static variables reduces object-orientation to absurdity. Sharing the same state across all instances of a class with the help of a static member variable is intrinsically not OOP because it breaks encapsulation, because an object is no longer in complete control of its state.

Of course, C++ is not a pure object-oriented programming language like Java or C#, and it is basically not forbidden to write procedural code in C++. But when you want to do that, you should be honest with yourself and consequently use simple free-standing procedures, functions, global variables, and namespaces.

My advice is to largely avoid static member variables and member functions.

One exception to this rule are private constants of a class, because they are read-only and do not represent an object’s state. Another exception are factory methods, that is, static member functions that create instances of an object, usually instances of the class type that serve as the namespace of the static member function.

280