Should I pass the Graphics to the Draw() function?
Well, when I saw this design, first thing which came into my mind was "why the heck does the TextBlock
have a Graphics attribute at all? Should it not be possible to draw the same block on two different graphics contexts? Should the TextBlock
object not have a lifetime which may be longer than the lifetime of the Graphics
object?"
So my answer is yes - it does not make much sense to me not to have a Graphics parameter in the Draw
function. This will imply to pass the Graphics
parameter into the DrawBlocks
method of the Page
, and some other method in your Section
, of course, but that is probably the correct design.
In fact, when your TextBlock
has more than a half dozen private methods, all called directly or indirectly from Draw
, and all of them use the same Graphics
object, it may be more convenient to buffer the Graphics
object passed by the Draw
method in a member variable, so you do not need to have the same Graphics
parameter in all of those methods. So keeping this attribute as a member might make sense (but this cannot be deciced from the small part of the text block class we see in your current model). And if you decide to keep this attribute, make sure you add a comment when this attribute is set and how long it is valid. The code then will look like this
void Draw(Graphics g)
{
graphics=g;
// ...
// call some members depending on "graphics"
// ...
graphics=null; // just in case, to avoid accessing an invalid graphics object
}
Alternatively, you could consider to introduce a helper class TextBlockDrawer
, which gets the Graphics
object and the TextBlock
passed as a constructor parameter, and encapsulates the whole drawing process. That way, you won't need a Graphics
member in your TextBlock
class any more, only in TextBlockDrawer
, and this attribute can be initialized in the constructor of that class. This design also makes a better separation between the data (TextBlock
) and the drawing process. The resulting code will look either like this:
class TextBlock
{
public void Draw(Graphics g)
{
var tbDrawer = new TextBlockDrawer(this,g);
tbDrawer.Draw();
}
}
or, by omitting the Draw
method in the TextBlock
completely, and reuse the TextBlockDrawer for different text blocks
:
class Page
{
// ...
public void DrawBlocks(Graphics g)
{
var tbDrawer = new TextBlockDrawer(g);
foreach(var tb in MyTextBlocks())
tbDrawer.Draw(tb);
}
}