mardi 31 janvier 2017

C++ Design Pattern Strategy - Save/Load

[1/2] Context

I'm using the Strategy Design Pattern to perform Save/Load within an application I've been coding since a couple of months...

Finally I come up with

  • a Model (sub-classed by Array and Graph among others)
  • two abstract I/O classes ModelReader and ModelWriter which are strategies that can be used to perform load/save.

Subsequently, I create several concrete strategies and thus were born ArrayXmlWriter and GraphXmlWriter which are dedicated to saving array and graph data to XML files. Now let's see the code snippets below and then I'll ask my questions.

// somewhere in ArrayXmlWriter

for(ArrayItem *item : array->items()) {
    // first write ModelItem attributes to a stream

    stream.writeAttribute("value",      item->value());
    stream.writeAttribute("brushColor", QVariant(item->brushColor()).toString());
    stream.writeAttribute("fontFamily", item->fontFamily());
    ...

    // then write ModelShapedItem attributes to a stream

    stream.writeAttribute("kind",    QVariant(item->shapeKind()).toString());
    stream.writeAttribute("rounded", QVariant(item->isRounded()).toString());
    ...

    // ArrayItem has no specific attributes
}

Indeed ArrayItem inherits from ModelShapedItem which inherits from ModelItem: ModelItem <-- ModelShapedItem <-- ArrayItem.

Now let's see the second snippet:

// somewhere in GraphXmlWriter

for(GraphVertex *vertex: graph->vertices()) {
    // first write ModelItem attributes to a stream

    same code as above

    // then write ModelShapedItem attributes to a stream

    same code as above

    // ModelNode has no specific attributes

    // then write GraphVertex attributes to a stream

    write successors to the stream
}

Here is the hierarchy involving the GraphVertex class: ModelItem <-- ModelShapedItem <-- ModelNode <-- GraphVertex.

Now here are my questions:

[2/2] Questions

Is there a way to avoid duplicating code (as shown above)? Indeed one way to achieve that will be to add a virtual function (taking the stream as parameter) to the ModelItem class. We could then override that function in sub-classes. That means if a GraphJsonWriter were to be created one day, the ModelItem class and its involved sub-classes would also be edited (since another virtual function should be added).

Now let's imagine the classes shown above but the concrete strategies are part of some library I'm dynamically linking to: that means I have no access to their code. How could one avoid code duplication without using dynamic_cast?

I'm not sure if I'm posting on the right forum. If I'm not, feel free to advise me by telling me which forum suits the most. I actually want to know if there is a way to achieve what I want to do.

Thanks and sorry if my english is not that good.

Aucun commentaire:

Enregistrer un commentaire