Ensuring that some logic is always being run before the user's overriding methods.
I'm writing a library and I have some abstract classes that can be binary serialized (and users can subclass them and further implement their serialization logic) e.g.
abstract class Base
{
protected int id;
public virtual void Serialize(BinaryWriter writer)
{
writer.Write(id);
}
}
class SomeonesClass : Base
{
public override void Serialize(BinaryWriter writer)
{
base.Serialize(writer);
// ...
}
}
Now, because writing the id is so important for all Base
objects, I want to ensure (force) that writer.Write(id)
gets called even in the subclasses written by users. So I don't even want to give them the option of calling base.Serialize(writer)
.
One way that I've done it was to split it into two methods:
abstract class Base
{
protected int id;
public void Serialize(BinaryWriter writer)
{
writer.Write(id);
InternalSerialize(writer);
}
protected virtual void InternalSerialize(BinaryWriter writer) { }
}
class SomeonesClass : Base
{
protected override void InternalSerialize(BinaryWriter writer)
{
}
}
The user could still avoid it by overriding Serialize
using the new
keyword etc, but at that point I'm fine to accept it.
Is this the best approach to achieve my intended design? The design being: send a very strong message to the users of the library that the id must be the first thing to be written.
1 Answer 1
Basically you have implemented the template method design pattern.
In your case your Serialize
method acts as the template method. It contains certain commands (before and/or after) the customisation points (usually referred as steps).
So, the answer for your question is yes, you have implemented it in a correct way.
Just a tiny note: It might make sense to declare your InternalSerialize
as abstract
rather than virtual
. Also you could work on its naming to better express your intent.
Explore related questions
See similar questions with these tags.
struct
s, Serde can automatically generate the implementation of the serialization and deserialization interfaces for you, at compile time. 5) Of course, both the serialization for the data type and the serialization format are ... \$\endgroup\$