Current Philosophy-Based Patterns: Minimalism
If we examine the process of dealing with an application's object model construction, we can identify two phases:
- The initial analysis of the relevant domain will be rather fast and will be based on the software engineers' common knowledge. For example, if our mission is to write a software application that manages the human resources issues of a furniture factory, we will almost by instinct add concepts such as "worker," "manager," "salary" and the like to the object model. Therefore, we can argue that the initial action, which establishes the semantic foundations for the object model, is deductive by its nature (we start from our own generic concepts).
- The second phase, however, could be classified as an inductive process -- we look at the details (the concrete objects) and find out about concepts and concept variants that we weren't aware of before getting into details. For example, we may find out that there are two types of "worker": "assistant" and "expert."
The second, inductive phase is in fact where most of the domain analysis work is done, and it actually never ends. This phase's goal is to bring us to a position where we are able to point to any object (concrete or abstract) that exists in the relevant domain and say which type is it (of course, within the limits forced by the extent of granularity that satisfies the application's needs). In other words, we would like to go through a process that will enable us to say about any object X that "X is Y."
Naturally, such an inductive, Aristotelian process will lead us to a situation in which an abstract object contains only the common properties of its inheritors. That is, we'll get a model that becomes "thinner" as we climb up the hierarchy. In other words, the current approach to object model construction is the Minimalism Approach (object properties are only the actual properties, and objects obey the principle of instantiation).
(See Sidebar 2. Aristotle's Categories and New Guidelines for Object Model Construction for an in-depth discussion of the philosophical basis for the above ideas.)
Suggested Philosophy-Based Pattern: Property Inhibition
The implementation of the Inhibition Pattern is based on the Maximalism approach, which allows defining a potential association between a property and an object (which means that the association is established before the property becomes an actual property). A potential property may be excluded from one of the potential property owner inheritors. This act of exclusion is called Inhibition.
In practice, the application is based on a class named PropertyManager, which contains the following components:
- The object property (e.g., the Fill class property that provides a description of the fill features for closed shapes)
- Property status -- Inhibited, Allowed
The PropertyManager receives the property and its status as an input of its constructor, and it provides one Getter for the property and another one for its status.
The said class operates on the basis of the following principles:
- Determining the status of the property is done only once, which is when the object that owns the property is being instantiated.
- The status of the property actually functions as an extension of class type. For example, we could sort out objects that have a particular actual property (the property status is in the Allowed state) from a list of objects held by their base class.
Property Inhibition Use Case
The example below illustrates the proposed solution for property inhibition, by an application that manages and displays several graphical forms.
At initialization time, the application instantiates a collection of graphical objects (outline, location, border, fill color and more), and displays them on a canvas (implemented in the Canvas class). The application provides the option to filter the shapes shown on canvas on the basis of the existence of potential properties (for example, filter the shapes by whether or not they have an actual Fill property).
The schematic outline of the object model is rather simple, and basically, it looks like this:
Figure 8. Schematic Outline of Object Model
The MyShape class is the base class of this object model. The classes that inherit from it represent the various shapes that are handled in this application -- MyCircle, MyRectangle, MyTriangle and MyPolyline. The special thing about this model is the fact that the MyShape class carries a list of PropertyManager objects, allowing the association of potential properties at the base class level. Besides that, we can see that the Canvas class manages a list of MyShape objects.
In this example, there are two potential properties:
- The shape's fill, implemented by the MyFill object
- The shape's outline, implemented by a list of MyLine objects
In order to demonstrate how the work with a potential property is being utilized, we will focus on just one shape: the circle.
Initialization of a Potential Parameter
During its initialization (its constructor execution), the Canvas object produces a number of MyShape objects (including a MyCircle object). The MyCircle initialization requires a blocking rectangle (a Rectangle object) and a fill definition (MyFill object) as its input.
As mentioned, the constructor of MyCircle receives two parameters:
- A blocking rectangle, which is unique to MyCircle, and therefore is kept in the MyCircle level
- A fill descriptor object (MyFill), which is passed to the base object (MyShape) in order to set the value of the MyShape's Fill potential parameter
Notice that MyCircle passes another parameter to the constructor of MyShape. This parameter stands for another potential parameter -- the lines collection that defines the shape's outline. This parameter is irrelevant to MyCircle, and therefore, it passes null.
The first action of the MyBase's constructor, which receives a collection of potential parameters as input, is to execute the InitializeStatuses function of its successor (in our case, MyCircle, which overrides the InitializeStatuses function defined in MyBase). The InitializeStatuses actually sets the status (Allowed, Inhibited) of each one of the potential parameters (in our case, MyCircle will set the status of the fill descriptor parameter to Allowed, and the status of the outline parameter will be set to Inhibited). Then, the constructor is ready to build the potential parameters themselves as PropertyManager parameters (
Using a Potential Parameter for Filtering
When the Canvas object receives a notification to redraw all the objects that it holds, it redraws them by using one of the following filters:
- AllShapes -- Show all shapes
- OnlyFillEnabledShapes -- Show only shapes that can be filled
- OnlyEdgeBasedShapes -- Show only shapes whose outlines are based on straight lines
For example, if the selected filter is OnlyFillEnabledShapes, the Canvas object will check the status of the relevant potential parameter:
shape.Fill.Status == PropertyManager.PropertyStatus.Allowed
and will decide, according to the answer, whether or not the object should be displayed.
I hope the ideas in this article have convinced you that studying philosophy is not just an academic exercise for software engineers. It is indeed a rich source for ideas about reality analysis, which can inform practical programming tasks such as object model construction.