Pure Fabrication - UML

Problem

What object should have the responsibility, when you do not want to violate High Cohesion and Low Coupling, or other goals, but solutions offered by Expert (for example) are not appropriate?

Object - oriented designs are sometimes characterized by implementing as software classes representations of concepts in the real - world problem domain to lower the representational gap; for example a Sale and Customer class. However, there are many situations in which assigning responsibilities only to domain layer software classes leads to problems in terms of poor cohesion or coupling, or low reuse potential.

Solution

Assign a highly cohesive set of responsibilities to an artificial or convenience class that does not represent a problem domain concept - something made up, to support high cohesion, low coupling, and reuse.

Such a class is a fabrication of the imagination. Ideally, the responsibilities assigned to this fabrication support high cohesion and low coupling, so that the design of the fabrication is very clean, or pure - hence a pure fabrication.

Finally, in English pure fabrication is an idiom that implies making something up, which we do when we're desperate!

Examples: NextGen Problem: Saving a Sale Object in a Database

For example, suppose that support is needed to save Sale instances in a relational database. By Information Expert, there is some justification to assign this responsibility to the Sale class itself, because the sale has the data that needs to be saved. But consider the following implications:

  1. The task requires a relatively large number of supporting database - oriented operations, none related to the concept of saleness, so the Sale class becomes incohesive.
  2. The Sale class has to be coupled to the relational database interface (such as JDBC in Java technologies), so its coupling goes up. And the coupling is not even to another domain object, but to a particular kind of database interface.
  3. Saving objects in a relational database is a very general task for which many classes need support. Placing these responsibilities in the Sale class suggests there is going to be poor reuse or lots of duplication in other classes that do the same thing.

Thus, even though Sale is a logical candidate by virtue of Information Expert to save itself in a database, it leads to a design with low cohesion, high coupling. and low reuse potential - exactly the kind of desperate situation that calls for making something up.

A reasonable solution is to create a new class that is solely responsible for saving objects in some kind of persistentstorage medium, such as a relational database; call it the PersistentStorage. This class is a Pure Fabrication - a figment of the imagination.

Notice the name: PersistentStorage. This is an understandable concept, yet the name or concept "persistentstorage" is not something one would find in the Domain Model. And if a designer asked a business - person in a store, "Do you work with persistentstorage objects?" they would not understand. They understand concepts such as "sale" and "payment." PersistentStorageis not a domain concept, but something made up or fabricated for the convenience of the software developer.

This Pure Fabrication solves the following design problems:

  1. The Sale remains well - designed, with high cohesion and low coupling.
  2. The PersistentStorageclass is itself relatively cohesive, having the sole purpose of storing or inserting objects in a persistent storage medium.
  3. The PersistentStorageclass is a very generic and reusable object.

Creating a pure fabrication in this example is exactly the situation in which their use is called for - eliminating a bad design based on Expert, with poor cohesion and coupling, with a good design in which there is greater potential for reuse.

Note that, as with all the GRASP patterns, the emphasis is on where responsibilities should be placed. In this example the responsibilities are shifted from the Sale class (motivated by Expert) to a Pure Fabrication.

Monopoly Problem: Handling the Dice

In the refactoring chapter, I used the example of dice rolling behavior (rolling and summing the dice totals) to apply Extract Method in the Player.takeTurn method. At the end of the example I also mentioned that the refactored solution itself was not ideal, and a better solution would be presented later.

In the current design, the Player rolls all the dice and sums the total. Dice are very general objects, usable in many games. By putting this rolling and summing responsibility in a Monopoly game Player, the summing service is not generalized for use in other games. Another weakness: It is not possible to simply ask for the current dice total without rolling the dice again.

But, choosing any other object inspired from the Monopoly game domain model leads to the same problems. And that leads us to Pure Fabrication - make something up to conveniently provide related services.

Although there is no cup for the dice in Monopoly, many games do use a dice cup in which one shakes all the dice and rolls them onto a table. Therefore, I propose a Pure Fabrication called Cup (notice that I'm still trying to use similar domain - relevant vocabulary) to hold all the dice, roll them, and know their total. The new design is shown in Figures. The Cup holds a collection of many Die objects. When one sends a roll message to a Cup, it sends a roll message to all its dice.

Figure 25.8 DCD for a Cwp

Figure 25.9 Using the Cup in the Monopoly game

Discussion

The design of objects can be broadly divided into two groups:

  1. Those chosen by representational decomposition.
  2. Those chosen by behavioral decomposition.

For example, the creation of a software class such as Sale is by representational decomposition; the software class is related to or represents a thing in a domain. Representational decomposition is a common strategy in object design and supports the goal of low representational gap. But sometimes, we desire to assign responsibilities by grouping behaviors or by algorithm, without any concern for creating a class with a name or purpose that is related to a real - world domain concept.

A good example is an "algorithm" object such as a TableOf Contents Generator, whose purpose is (surprise!) to generate a table of contents and was created as a helper or convenience class by a developer, without any concern for choosing a name from the domain vocabulary of books and documents. It exists as a convenience class conceived by the developer to group together some related behavior or methods, and is thus motivated by behavioral decomposition.

To contrast, a software class named TableOf Contentsis inspired by representational decomposition, and sMould contain information consistent with our concept of the real domain (such as chapter names).

Identifying a class as a Pure Fabrication is not critical. It's an educational concept to communicate the general idea that some software classes are inspired by representations of the domain, and some are simply "made up" as a convenience for the object designer. These convenience classes are usually designed to group together some common behavior, and are thus inspired by behavioral rather than representational decomposition. Said another way, a Pure Fabrication is usually partitioned based on related functionality, so it is a kind of function - centric or behavioral object.

Many existing object - oriented design patterns are examples of Pure Fabrications: Adapter, Strategy, Command, and so on [GHJV95].

As a final comment worth reiterating: Sometimes a solution offered by Information Expert is not desirable. Even though the object is a candidate for the responsibility by virtue of having much of the information related to the responsibility, in other ways, its choice leads to a poor design, usually due to problems in cohesion or coupling.

Benefits

  • High Cohesion is supported because responsibilities are factored into a finegrained class that only focuses on a very specific set of related tasks.
  • Reuse potential may increase because of the presence of fine - grained Pure Fabrication classes whose responsibilities have applicability in other applications.

Behavioral decomposition into Pure Fabrication objects is sometimes overused by those new to object design and more familiar with decomposing or organizing software in terms of functions. To exaggerate, functions just become objects. There is nothing inherently wrong with creating "function" or "algorithm" objects, but it needs to be balanced with the ability to design with representational decomposition, such as the ability to apply information Expert so that a representational class such as Sale also has responsibilities.

Information Expert supports the goal of co - locating responsibilities with the objects that know the information needed for those responsibilities, which tends to support lower coupling. If overused, Pure Fabrication could lead to too many behavior objects that have responsibilities not co - located with the information required for their fulfillment, which can adversely affect coupling. The usual symptom is that most of the data inside the objects is being passed to other objects to reason with it.

Related Patterns and Principles

  • Low Coupling.
  • High Cohesion.

A Pure Fabrication usually takes on responsibilities from the domain class that would be assigned these responsibilities based on the Expert pattern.

All GoF design patterns [GHJV95], such as Adapter, Command, Strategy, and so on, are Pure Fabrications.

Virtually all other design patterns are Pure Fabrications.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

UML Topics