Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Adding methods to a polymorphic class hierarchy without violating SRP?

I have a design issue that I constantly keep encountering.

For the sake of illustration, let's assume that I have a polymorphic class hierarchy

class A { public: virtual ~A() {} ... };
class B: public A { ... };
class C: public B { ... };
class D: public A { ... };
...

I want to be able to print instances of these classes in a polymorphic way, i.e. each class has its own way of printing itself. The obvious way of achieving this would be to add

virtual void print(OutputStream &os) = 0;

into the base class and override this method in every subclass. However, if the original responsibility of the classes is not related to printing, this will add another responsibility to them, thus violating SRP.

My question is: what is a proper way of achieving the desired behavior without violating SRP?

In this post, a solution based on the Visitor design pattern is proposed. However, then I would need to create a class which has to know about every subclass of A. I would like to be able to add and remove subclasses without a need to always modify the visitor.

Is there some other, SRP-preserving way than the two ways described above?

like image 362
s3rvac Avatar asked Mar 24 '23 01:03

s3rvac


2 Answers

There is an acyclic visitor pattern that eliminates the need to know about every subclass. It relies on dynamic_cast, but may be what you need.

like image 90
Juraj Blaho Avatar answered Apr 06 '23 20:04

Juraj Blaho


There is nothing wrong with a class printing itself. It does not violate SRP because printing does not constitute a responsibility.

Remember that responsibility is defined as a reason to change. You don't change a class because your requirements for printing change. The class should only send name-value pairs to the entity responsible for printing, called the formatter. This procedure of sending name-value pairs never ever changes by itself. Any changes in it are only prompted by other changes, unrelated to printing (when you e.g. add a field, you also add its representation to the printing procedure).

The formatter should know nothing about the classes it prints, but simply present the name-value pairs according to some set of requirements. The formatter changes when the printing requirements change. Therefore printing would be the sole responsibility of the formatter.

like image 42
n. 1.8e9-where's-my-share m. Avatar answered Apr 06 '23 22:04

n. 1.8e9-where's-my-share m.