design pattern for "save" - c++

I'm currently working on a "save" mechanism, which allows a user to save the project his working on on hard disc. The output will be a XML file containing all kinds of data.
Now our project structure is about to change and we need to write a new xml file (create a new save method).
So now here comes the challenge: When saving I want the user to be able to choose which file format he will be creating (version1 (old) or version2 (new)).
Does anyone now how to achieve that? Is there a suitable design pattern around?
Remarks:
- The data we are saving can be seen as unrelated blocks, so it would actually be easy to exchange an old block with a new one.
- The whole goal of the thing is, it should be readable again when loading an old project. (I assume this can be done by tags, and just react on tags when loading?)

This sounds like a good application for the Strategy pattern.
You would create an abstract base class FileFormat (the Strategy interface) with two virtual functions, projectToXml and xmlToProject, which are supposed to turn your internal project representation into XML or vice versa.
Then you create two implementing subclasses FileFormatNew and FileFormatLegacy (these are the concrete strategies).
Your save functions would then additionally require an instance of FileFormat, and call the corresponding method of that object to do the data conversion. Your load function could choose the strategy to use by examining the XML tree for something which tells it which version it is.
And when you ever need to support another file format, you just have to create a new class which is a subclass of FileFormat.
Addendum after the exchange in the comments
When you are going to have a lot of versions with very small differences and you still want to use the Strategy pattern, you could make the FileFormat a composite of multiple strategies: A CircleStragegy, a RectangleStrategy, a LineStrategy etc.. In that case I wouldn't use different classes for different versions of the FileFormat. I would create a static factory function for each version which returns a FileFormat with the Strategy objects used in that version.
FileFormat FileFormat::createVersion1_0() {
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_1() {
// the 1.1 version introduced the new way to save lines
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_2() {
// 1.2 uses the new format to save circles
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyNew(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_3() {
// 1.3 uses a new format to save rectangles, but we realized that
// the new way to save lines wasn't that good after all, so we
// returned to the old way.
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyNew(),
new RectangleStragegyNew()
);
}
Note: In real code you would of course use more descriptive suffixes than "Old" and "New" for your strategy class names.

Related

Use Arrow schema with parquet StreamWriter

I am attempting to use the C++ StreamWriter class provided by Apache Arrow.
The only example of using StreamWriter uses the low-level Parquet API i.e.
parquet::schema::NodeVector fields;
fields.push_back(parquet::schema::PrimitiveNode::Make(
"string_field", parquet::Repetition::OPTIONAL, parquet::Type::BYTE_ARRAY,
parquet::ConvertedType::UTF8));
fields.push_back(parquet::schema::PrimitiveNode::Make(
"char_field", parquet::Repetition::REQUIRED, parquet::Type::FIXED_LEN_BYTE_ARRAY,
parquet::ConvertedType::NONE, 1));
auto node = std::static_pointer_cast<parquet::schema::GroupNode>(
parquet::schema::GroupNode::Make("schema", parquet::Repetition::REQUIRED, fields));
The end result is a std::shared_ptr<parquet::schema::GroupNode> that can then be passed into StreamWriter.
Is it possible to construct and use "high-level" Arrow schemas with StreamWriter? They are supported when using the WriteTable function (non-streaming) but I've found no examples of its use with the streaming API.
I, of course, can resort to using the low-level API but it is extremely verbose when creating large and complicated schema and I would prefer (but not need) to use the high-level Arrow schema mechanisms.
For example,
std::shared_ptr<arrow::io::FileOutputStream> outfile_;
PARQUET_ASSIGN_OR_THROW(outfile_, arrow::io::FileOutputStream::Open("test.parquet"));
// construct an arrow schema
auto schema = arrow::schema({arrow::field("field1", arrow::int64()),
arrow::field("field2", arrow::float64()),
arrow::field("field3", arrow::float64())});
// build the writer properties
parquet::WriterProperties::Builder builder;
auto properties = builder.build()
// my current best attempt at converting the Arrow schema to a Parquet schema
std::shared_ptr<parquet::SchemaDescriptor> parquet_schema;
parquet::arrow::ToParquetSchema(schema.get(), *properties, &parquet_schema); // parquet_schema is now populated
// and now I try and build the writer - this fails
auto writer = parquet::ParquetFileWriter::Open(outfile_, parquet_schema->group_node(), properties);
The last line fails because parquet_schema->group_node() (which is the only way I'm aware of to get access to the GroupNode for the schema) returns a const GroupNode* whereas ParquetFileWriter::Open) needs a std::shared_ptr<GroupNode>.
I'm not sure casting-away the constness of the returned group node and forcing it into the ::Open() call is an officially supported (or correct) usage of StreamWriter.
Is what I want to do possible?
It seems that you need to use low-level api for StreamWriter.
a very tricky way:
auto writer = parquet::ParquetFileWriter::Open(outfile_, std::shared_ptr<parquet::schema::GroupNode>(const_cast<parquet::schema::GroupNode *>(parquet_schema->group_node())), properties);
you may need to converter schema manually.
source code cpp/src/parquet/arrow/schema.cc may help you.
PARQUET_EXPORT
::arrow::Status ToParquetSchema(const ::arrow::Schema* arrow_schema,
const WriterProperties& properties,
std::shared_ptr<SchemaDescriptor>* out);

Is it possible to inject a component that doesn't have a prefab/GameObject associated with it?

I have a game object (a cube, let's say) which exists in the scene, and I want it to have an injectable component. I want to be able to say, for example: My cube has an IShotFirer member, which can resolve to either a BoomShotFirer or a BangShotFirer MonoBehavior component, both of which implement IShotFirer. When binding happens, I want this component to be added to the cube object.
public class CubeBehavior : MonoBehaviour
{
[Inject]
private IShotFirer shotFirer;
}
Is it possible to do this without 1) needing an existing prefab which contains one of these Bang/Boom components, or 2) needing an existing scene object which has one of these components attached?
In other words, I want to be able to dynamically add the component to my game object depending on the bindings, and not relying on anything other than the script files which define either BoomShotFirer or BangShotFirer. But the docs seem to imply that I need to find an existing game object or prefab (e.g. using .FromComponentsInChildren(), etc.)
Is it possible to do this without 1) needing an existing prefab which
contains one of these Bang/Boom components, or 2) needing an existing
scene object which has one of these components attached?
Yes, it is.
Zenject provides a host of helpers that create a new components and bind them -- quoting the docs:
FromNewComponentOnRoot - Instantiate the given component on the root of the current context. This is most often used with GameObjectContext.
Container.BindInterfacesTo<BoomShotFirer>().FromNewComponentOnRoot();
FromNewComponentOn - Instantiate a new component of the given type on the given game object
Container.BindInterfacesTo<BoomShotFirer>().FromNewComponentOn(someGameObject);
FromNewComponentOnNewGameObject - Create a new game object at the root of the scene and add the Foo MonoBehaviour to it
Container.BindInterfacesTo<BoomShotFirer>().FromNewComponentOnNewGameObject();
For bindings like this one that create new game objects, there are also extra bind methods you can chain:
WithGameObjectName = The name to give the new Game Object associated with this binding.
UnderTransformGroup(string) = The name of the transform group to place the new game object under.
UnderTransform(Transform) = The actual transform to place the new game object under.
UnderTransform(Method) = A method to provide the transform to use.
That list is not even exhaustive, be sure to check the readme and the cheatsheet (from both of which I have extracted the info above).
Also understand that, as usual, you can append .AsSingle(), .AsTransient() and .AsCached() to achieve the desired result.

How to exchange custom data between Ops in Nuke?

This questions is addressed to developers using C++ and the NDK of Nuke.
Context: Assume a custom Op which implements the interfaces of DD::Image::NoIop and
DD::Image::Executable. The node iterates of a range of frames extracting information at
each frame, which is stored in a custom data structure. An custom knob, which is a member
variable of the above Op (but invisible in the UI), handles the loading and saving
(serialization) of the data structure.
Now I want to exchange that data structure between Ops.
So far I have come up with the following ideas:
Expression linking
Knobs can share information (matrices, etc.) using expression linking.
Can this feature be exploited for custom data as well?
Serialization to image data
The custom data would be serialized and written into a (new) channel. A
node further down the processing tree could grab that and de-serialize
again. Of course, the channel must not be altered between serialization
and de-serialization or else ... this is a hack, I know, but, hey, any port
in a storm!
GeoOp + renderer
In cases where the custom data is purely point-based (which, unfortunately,
it isn't in my case), I could turn the above node into a 3D node and pass
point data to other 3D nodes. At some point a render node would be required
to come back to 2D.
I am going into the correct direction with this? If not, what is a sensible
approach to make this data structure available to other nodes, which rely on the
information contained in it?
This question has been answered on the Nuke-dev mailing list:
If you know the actual class of your Op's input, it's possible to cast the
input to that class type and access it directly. A simple example could be
this snippet below:
//! #file DownstreamOp.cpp
#include "UpstreamOp.h" // The Op that contains your custom data.
// ...
UpstreamOp * upstreamOp = dynamic_cast< UpstreamOp * >( input( 0 ) );
if ( upstreamOp )
{
YourCustomData * data = yourOp->getData();
// ...
}
// ...
UPDATE
Update with reference to a question that I received via email:
I am trying to do this exact same thing, pass custom data from one Iop
plugin to another.
But these two plugins are defined in different dso/dll files.
How did you get this to work ?
Short answer:
Compile your Ops into a single shared object.
Long answer:
Say
UpstreamOp.cpp
DownstreamOp.cpp
define the depending Ops.
In a first attempt I compiled the first plugin using only UpstreamOp.cpp,
as usual. For the second plugin I compiled both DownstreamOp.cpp and
UpstreamOp.cpp into that plugin.
Strangely enough that worked (on Linux; didn't test Windows).
However, by overriding
bool Op::test_input( int input, Op * op ) const;
things will break. Creating and saving a Comp using the above plugins still
works. But loading that same Comp again breaks the connection in the node graph
between UpstreamOp and DownstreamOp and it is no longer possible to connect
them again.
My hypothesis is this: since both plugins contain symbols for UpstreamOp it
depends on the load order of the plugins if a node uses instances of UpstreamOp
from the first or from the second plugin. So, if UpstreamOp from the first plugin
is used then any dynamic_cast in Op::test_input() will fail and the two Op cannot
be connected anymore.
It is still surprising that Nuke would even bother to start at all with the above
configuration, since it can be rather picky about symbols from plugins, e.g if they
are missing.
Anyway, to get around this problem I did the following:
compile both Ops into a single shared object, e.g. myplugins.so, and
add TCL script or Python script (init.py/menu.py)which instructs Nuke how to load
the Ops correctly.
An example for a TCL scripts can be found in the dev guide and the instructions
for your menu.py could be something like this
menu = nuke.menu( 'Nodes' ).addMenu( 'my-plugins' )
menu.addCommand('UpstreamOp', lambda: nuke.createNode('UpstreamOp'))
menu.addCommand('DownstreamOp', lambda: nuke.createNode('DownstreamOp'))
nuke.load('myplugins')
So far, this works reliably for us (on Linux & Windows, haven't tested Mac).

Use a MSHFlexGrid with non-database data and still define the shape

I am trying to use the Microsoft Hierarchical FlexGrid (MSHFlexGrid) in a Visual C++ (VS 2005). I have the grid shown, and I can manually add data to the individual cells. However, according to online documentation I've read, I should be able to show the hierarchical nature of the data (hence MSHFlexGrid instead of MSFlexGrid) by defining the SHAPE as the RecordSource. I can do that fine (by using the put_RecordSource method of the grid object), however I'm at a loss as to how to add the actual data.
I've read that the best way to do this is to use an ADO Data Control (ie ADODC) component and bind it as the DataSource for the Grid. You can then specify "provider=msdatashape;data provider=none;" as the provider of the DataControl and fill it with data. If I were doing SQL, I'd specify my SELECT query as the RecordSource, then call Refresh() and let the control load the data.
However, my data is in custom objects. I know what needs to be displayed, I'm just at a loss as to the best way to insert the data into the FlexGrid and still use the built in features of the control. I'm open to any suggestions, but I need to keep the data local (ie no JET, Access, etc).
Here's some code:
In header:
....
// Variable to control the Flex Grid component
CMshflexgrid1 m_grid; //generated by wizard from the MSHFlexGrid component
// to control the data source hierarchical information
CAdodc1 m_adodc1;
....
In cpp:
....
BOOL MyDialogClass::OnInitDialog()
{
CDialog::OnInitDialog();
m_grid.Clear();
CString strCn = "provider=msdatashape;data provider=none;";
m_adodc1.put_ConnectionString(strCn);
CString BackupOfRecordSource = "";
BackupOfRecordSource = m_adodc1.get_RecordSource();
//CString strShape = "SHAPE APPEND new adInteger As PID, New adVarChar(10) As StudentName, ((SHAPE APPEND new adInteger As ChID, New adVarChar(10) As Course, ((SHAPE APPEND new adInteger As GrndChID, New adBSTR As Description) RELATE ChID TO GrndChID) As GrandChild) RELATE PID TO ChID) AS Child";
CString strShape = "SHAPE APPEND new adInteger As PID, New adVarChar(10) As StudentName";
m_adodc1.put_RecordSource(strShape);
m_adodc1.Refresh();
m_grid.Refresh();
BackupOfRecordSource = m_adodc1.get_RecordSource(); //returns the strShape that I just put in
//ADD RECORDS HERE! HOW?
return TRUE;
}
The sample talked about building an ADODB.Recordset and use it as the data source of ADODC. The code you give is building a SQL and use it as the data source of ADODC. I don't think you can replace an ADODB.Recordset with a string.

Displaying polymorphic classes

I have an existing app with a command-line interface that I'm adding a GUI to. One situation that often comes up is that I have a list of objects that inherit from one class, and need to be displayed in a list, but each subclass has a slightly different way of being displayed.
Not wanting to have giant switch statements everywhere using reflection/RTTI to do the displaying, each class knows how to return its own summary string which then gets displayed in the list:
int position = 0;
for (vector<DisplayableObject>::const_iterator iDisp = listToDisplay.begin(); iDisp != listToDisplay.end(); ++iDisp)
cout << ++position << ". " << iDisp->GetSummary();
Similar functions are there to display different information in different contexts. This was all fine and good until we needed to add a GUI. A string is no longer sufficient - I need to create graphical controls.
I don't want to have to modify every single class to be able to display it in a GUI - especially since there is at least one more GUI platform we will want to move this to.
Is there some kind of technique I can use to separate this GUI code out of the data objects without resorting to RTTI and switch statements? It would be nice to be able to take out the GetSummary functions as well.
Ideally I'd be able to have a heierarchy of display classes that could take a data class and display it based on the runtime type instead of the compile time type:
shared_ptr<Displayer> displayer = new ConsoleDisplayer();
// or new GUIDisplayer()
for (vector<DisplayableObject>::const_iterator iDisp = listToDisplay.begin(); iDisp != listToDisplay.end(); ++iDisp)
displayer->Display(*iDisp);
I don't think this will solve your problem of not needing to write the code, but you should be able to abstract the GUI logic from the data objects.
Look at a Visitor pattern (http://en.wikipedia.org/wiki/Visitor_pattern) it will allow you to add code to an existing object without changing the object itself. You can also change the visitor based on the platform.