Bryan White wrote:
I don't like flags. The idea of OO stuff is encapsulation.
Is there any reason that part of such encapsulation is not using some sort of state flags? MANY of the implementations in the class library - especially those that wrap the Windows Common Controls - use state flags / variables and act accordingly. It's just part of the encapsulation.
I have no problem with flags describing an objects INTERNAL state. You are correct, and I agree. I should probably have said "I don't like flags holding the state of, or describing, OTHER objects". This is hinted at by my following sentence (encapsulation).
If (as in this case) an object(PrintDocument) is being activated from another one(either PreviewPrintController/PrintPreviewDialog or StandardPrintController/PrintDialog), then rather than storing a flag about which one activated it (and causing headaches if you decide Preview = !Standard and a third one is added), I feel that it is better to just store the controller/dialog object as a 'parent object'. Then, Microsoft decided to specifically hide this 'parent object', which I find VERY FRUSTRATING (as you can probably guess from the tone of my earlier response. BTW my own technique for defining an item as "this is public but you probably shouldn't be using it" is to prefix the name with an underscore "_". This may not be part of any standard, but hopefully makes people (and myself in a week's time!) think twice before using it.)
If this hidden member did not exist, then rather than create a flag I would still prefer to:
- create a derived class from PrintDocument (called PrintDocumentWithActivator?) with a member of type object called something like 'parent' or 'activator'.
- store the PrintPreviewDialog(or other activator) object in it
- test this object in the PrintPage event.
I feel that this follows the Open-Closed Principle(OCP) better than a flag. Once the 'activator' object is defined, there need be no further changes in the class if, say, a PrintTo3DEngraverDialog came along later, and the programmer wanted a registered trade mark engraved bottom left rather than a copyright notice printed bottom right.
If the flag was held in the app class, then it would be impossible to decide to how to print the PrintDocument object by just referring to that particular instance; you would need TWO objects to decide (difficult when just one object is passed in an event handler), and in danger of violating the Dependency Inversion Principle(DIP); why should the app know or care how an object is being printed?
This in itself would violate the Interface Segregation Principle(ISP) by polluting the app class with potentially dozens/hundreds of flags for each type of operation that might happen 'lower down'.
Should the PrintDocument be implemented in another application - surprise! The new app needs a flag defined! We now have run into Granularity issues of the Reuse/Release Equivalence Principle(REP) & Common Reuse Principle(CRP).
Yes, flags may be used for INTERNAL states, but NOT for states of OTHER objects. Putting a flag in the app, as suggested by yourself, is NOT a good way to go; the app should neither know nor care which button (Print or PrintPreview) was pressed.