1

I have been implementing a software driver for an external (from my microcontroller point of view) chip communicating with my microcontroller over I2C. From the higher perspective the chip is a collection of some registers which can be read or written. This idea bring me to the following driver design:

enter image description here

The chip requires some kind of configuration after power-up. This configuration basically consists of writting given data into specified registers. Unfortunatelly the writting process occurs via communication channel where the written data can be corrupted. So it is not sufficient to blindly send the data. Instead it is necessary to read them back and check to see that the written data equals the sent of them to be sure the writting operation has been successfully done. I have decided to encapsulate this configuration algorithm into special class:

enter image description here

The intention is that the configureDevice method of the Configurator will be invoked from the update method which is invoked in periodic manner. What I am now thinking about is how to ensure the access of the Configurator object to the private Register objects for the configuration.

My first idea was to create Configurator object as a private member inside the Device, declare Configurator as a friend of Device and pass pointer to the Device into the Configurator. Second idea was the visitor design pattern. Which is probably cleaner solution. Do you think that visitor design pattern usage is justified in this case?

1
  • 3
    You don't have to declare Configurator as a friend of Device; instead, you can pass the register_map to Configurator's configureDevice method (e.g. as an array (pointer/ref), or maybe as an iterator). That way, the Configurator class doesn't need to worry about where to find the registers or how to access them (it leaves that responsibility to its clients, and is more focused as a result). The Visitor pattern is an overkill for this and doesn't really fit the "shape" of this problem. Feb 17, 2021 at 20:07

2 Answers 2

3

You need a concept of a device configuration — which could be encapsulated as data/state — and the primitive abilities to write a configuration, and to verify a configuration — and perhaps at a higher level of abstraction some concept of write & rewrite the configuration until it takes or until you give up.

I don't see how a visitor will help; visitors are useful when there's lots of different desired behaviors based on differentiation of types, and when you don't want to modify the original types to accommodate adding new behaviors.

From the visitor pattern article at wikipedia:

What problems can the Visitor design pattern solve?

  • It should be possible to define a new operation for (some) classes of an object structure without changing the classes.

When new operations are needed frequently and the object structure consists of many unrelated classes, it's inflexible to add new subclasses each time a new operation is required because "[..] distributing all these operations across the various node classes leads to a system that's hard to understand, maintain, and change."

What solution does the Visitor design pattern describe?

  • Define a separate (visitor) object that implements an operation to be performed on elements of an object structure.
  • Clients traverse the object structure and call a dispatching operation accept (visitor) on an element — that "dispatches" (delegates) the request to the "accepted visitor object". The visitor object then performs the operation on the element ("visits the element").

This makes it possible to create new operations independently from the classes of an object structure by adding new visitor objects.

The nature of the Visitor makes it an ideal pattern to plug into public APIs, thus allowing its clients to perform operations on a class using a "visiting" class without having to modify the [original] source.

Moving operations into visitor classes is beneficial when

  • many unrelated operations on an object structure are required,
  • the classes that make up the object structure are known and not expected to change,
  • new operations need to be added frequently,
  • an algorithm involves several classes of the object structure, but it is desired to manage it in one single location,
  • an algorithm needs to work across several independent class hierarchies.
2
  • thank you very much for your reaction. Please can you tell me what do you think about my first idea with the friend class? Thanks in advance. Feb 17, 2021 at 19:57
  • I described what I think you need in first paragraph. What I'm saying is that rather than a configurator class (behavior), I suggest the concept of a configuration (data). The device class should accept a configuration and do the write & read until satisfied. If the read can fail as well as the write, all of that should be encapsulated so that the consumer of the classes can create a configuration and ask for that to be configured to the device by the device (management) object.
    – Erik Eidt
    Feb 18, 2021 at 1:59
2

My first idea was to create Configurator object as a private member inside the Device, declare Configurator as a friend of Device and pass pointer to the Device into the Configurator.

Does the Configurator class need access to the entire Device object, or does it just need to know the register_map? If it is enough for the Configurator class to have a pointer to the register_map, then you can add a private Configurator member to your Device class and pass a pointer to the register_map into the Configurator.

Second idea was the visitor design pattern. Which is probably cleaner solution. Do you think that visitor design pattern usage is justified in this case?

No, the visitor design pattern is not justified here, as indicated in the answer by @ErikEidt

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.