Question

How do you decide when and how to violate the single responsability principle?

For example, let's say I have a network camera with the following interface (interface kept stupid and "wrong" for simplicity):

class Camera
{
  string user();
  void set_user(string user);

  string password();
  void set_password(string password);

  string url();
  void set_url(string url);

  image take_snapshot();

  bool reboot();
}

This looks natural, but it looks like the Camera class has 3 responsabilties: store metadata, take snapshot, reboot. Following the SRP, you could write it like this:

class Camera
{
  string user();
  void set_user(string user);

  string password();
  void set_password(string password);

  string url();
  void set_url(string url);
}

image take_snapshot(camera c);
bool reboot_camera(camera c);

Here stuffs are neatly separated in terms of responsabilities, but now it looks very much like C with dumb structs and functions... which begs the question as to why we need OOP in the first place.

How do you balance between convenience and SRP?

[EDIT]

@stjin idea was shown as an answer by @John Zwinck

Was it helpful?

Solution

I'd write your example this way:

class Session
{
public:
  Session(string url, string user, string password);
};

class Camera
{
public:
  Camera(Session);

  image take_snapshot();
  bool reboot();
};

The main idea here is to separate authentication and session/endpoint definition (and perhaps connection) from the camera controls. The class Camera now more closely models a real camera: it has something like a power button and a shutter button. The virtualization of the camera is elsewhere, on its own. This also makes it more obvious what to do if someone wants to make a USB session for a different camera, etc.

A secondary idea here is that objects are created with valid state from the beginning. There is here no way to configure a Camera without a password for example, so calling take_snapshot() without credentials is simply not possible. Of course the credentials may be invalid, but that can be checked by some method which might be called in one of the constructors.

As an aside, there is nothing wrong with free functions. OOP is overrated, we all know it, and you shouldn't feel any need to apologize if free functions work in your use case. Dumb structs can be better than pointless getter and setters--especially if you're not building a reusable library that has ABI compatibility requirements.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top