Object-oriented design intuitively revolves around the specification and elicitation of objects. The purpose of OOD is not only to determine what objects are needed, but the methods and attributes of these objects. Relationships between the objects also must be determined, and in some manner documented. This documentation, even though it is not intended to be executed by a computer, must be capable of human understanding.
7.6.1 Abstractions
A model is essentially an abstraction of the real world. It captures only the essential and relevant characteristics of the real world (Jia 2003). Abstraction should lead to the development of models. These models should be able to mimic the behavior and form of the physical world when implemented. Just like the real world understanding of an entity, an abstraction can only maintain a portion of the actual information concerning the entity. For example, if you were to abstract a chair (the common ordinary dining room table type) into a class you very easily could come up with attributes such as height, weight, color, if it can swivel, the material it is made out of etc. This may sound like a perfectly complete, including any other items you may realized were missing from my list. Yet, there are many more items that could be added to both our lists; where the raw materials origi-nated, density, age, manufacturer and how much dust resides on it. The list could go on forever and that is why only the important aspects of the chair (or anything else) should be included in the abstraction.
DrawableObject
MultiPointObject TwoPointObject
Polygon Curve Line Rectangle Oval
Fig. 7.3 Top down design
136 7 System Design
7.6.2 Architecture
Large systems can be decomposed into sub-systems that provide some related set of services. The initial design process of identifying these sub-systems and establishing a framework for sub-system control and communication is called architectural design (Sommerville 2004). Object-oriented Architecture is very close in comparison to that of the more commonly known architecture, that of homes and buildings.
This parallel is very useful for constructing mental images of software tecture. Software architecture suffers from the same caveats of traditional archi-tecture. Some of the major parallels are that:
• Different models exist for both software architecture and a building architect.
• Bad design cannot be made right through implementation.
• Elegant design does not guarantee proper implementation.
Using the above listed correlations between designing object-oriented software and designing a home, it is easier to see the most important aspect is a well designed architecture. Software though may not be tangible in the same sense that a building is, but it still has very real implications. Poorly architected software can cause fiscal harm possibly easier than poorly architected buildings.
7.6.3 Design Patterns
A design pattern represents a generic and reusable solution to a recurring prob-lem. Design Patterns were first published en masse by Gamma et al. in 1995.
Gamma et al. were able to separate design patterns into three distinct groups (Jia 2003):
1. Creational patterns: concern the creation of objects.
2. Structural patterns: these patterns deal with the composition of objects.
3. Behavioral patterns: these patterns reflect the interactions of objects within a system.
7.6.4 Modularity
Modules, or classes, are the most important derivation of object-oriented design.
This being said, modularity is the use of divide and conquer to create a set of cohesive and loosely coupled modules (Jia2003). This means that each module is an entity on its own connected to the other modules in the system by simple and loose connections. To do this, each module performs a specific function or serves a unique purpose. Any module in this system can be replaced by any other module that maintains the same interfaces for interconnecting modules.
7.6.5 Encapsulation
Modularity is achieved mainly by the separation of interface from implementation.
This separation is known as encapsulation. With a correctly encapsulated object the developer does not need to know how the internals of the class work, they need to merely know the input parameters and the corresponding return type. Each of these independent modules allows for greater simplicity of the system due to property that you can remove any module and replace this module with another that offers the same interfaces. This replacement and interface agreement does not, however, result in guaranteed simplicity. This is due to the fact that the func-tionality of the object can be obscured by poor naming conventions and insufficient documentation. As the internals of the object are unknown it may be difficult to determine its correct use when documentation is unavailable.
Encapsulation is a method of hiding implementation details from the consumers of the object. Just because the internal implementation may not be available to anyone using the object, this does not mean that you can write poor code internally and not worry since the interface is the only portion that is observed. The effects of your programming will be noticed and all interfaces rely on proper internal composition of the class to create satisfactory results.
7.6.6 Refinement
As a project, the progress from concept to delivery can make many details change or become clearer. This extends to not only the project understanding and implementation as a whole, but to each component, class, object and subsystem. A well designed and implemented architecture will permit refinement. Refinement is a modification to the system resulting from any attitude, desire, or requirement (functional or non-functional), as well as any intrinsic or extrinsic event that concerns the project. Although it is impossible to prevent alterations to specifi-cations after a project has begun, it is the part of good design practice to have the understanding how these concepts will be handled.
Business models are necessary to convey business ideas from the client to the design and implementation teams. These models should not be static, but dynamic in nature to provide for the most fluid and natural process of implementing of changes. Keeping track of requirements using use case diagrams and a list of requirements is a simple and inexpensive way of maintaining system functionality with the client’s expectations (Schach 2008). Since Object-Oriented Design is iterative, these changes can be implemented in varying stages and they are not always necessarily required to be rushed to the production floor.
138 7 System Design
7.6.7 Class Design
There are various design principles that allow for classes and their objects to gain the most from object-oriented design. Classes describe the attributes and methods of objects. Collectively classes can be enumerated with those that they are related to. Collective class enumeration details the interactions of the classes and their relationships with one another (Fig.7.4).
How to get from a design concept to the model shown above can be a cum-bersome process. Schach points to an iterative and incremental three step approach (Schach 2008). This method is described in the Architectural Design portion of this chapter. However, at this point it is useful to know that successful design methodologies allow for the maximum amount of reuse and growth with the least complexity.
7.6.8 Subsystems and Classes
A correct modular design revolves around a sliding scale of granularity. This granularity can be as coarse as the entire project or as fine as a single class, or even smaller with the attribute of a class. Subsystems are one of the most useful levels of abstraction when a developer wishes to gain an overview of how to compo-nentize a system. Subsystems are merely a collection of modules where some are visible to other subsystems and some modules are not externally visible (Booch 1994). These subsystems and the classes that compose them provide many benefits for developers that include:
1. The ability to logically break a system into segments more easily understood by people. Fig. 7.4 Example of a class
diagram
2. The ability to isolate errors based on the component failure.
3. The ability to loosely couple subsystems in the same way classes are loosely coupled providing the ability to replace one subsystem with another offering the same interfaces (Fig.7.5).
Like anything else poorly designed or implemented, subsystems that are of bad quality provide little to no benefit to anyone. There are a few considerations to make the optimal subsystem organization. First, think of the system as interactive parts, such as what parts can function without the others (normally the ones seen outside of the system). You must also consider if there is logic carried out that can be implemented via inputs and outputs. This can be seen in the ‘‘Planning’’ module of Fig.7.5. The gardener in this scenario would provide the planning information, such as the number of plants and their variety, and the planning module would provide the pertinent information to each of the modules below it using the appropriate interfaces. There may also be accessible controls. In this scenario they are grouped in the ‘‘Devices’’ module.
7.6.9 Services and Subsystem Interfaces
Each module must provide some service or functionality otherwise they would not need to be included in the system. To do this, each service needs an interface to the service requestor(s). This interface is a subsystem interface, and subsystem interfaces should function similarly to those of class level interfaces. They should provide the smallest pieces of data necessary as well as retain only one functionality.
Gardener
Motif
Planning
Nutritionist Database Climate
control
Devices Fig. 7.5 Top-Level Module
Diagram (Booch1994)
140 7 System Design
7.6.10 Coupling and Cohesion
Couplingmeasures the degree of independence and interaction between modules.
A module’s independence results from its freedom from the modification of its variables by other objects (Burch 1992). Thus, if two modules have very little interaction they are said to be loosely coupled. The opposite being tightly cou-pled, or when two modules have a great level of interaction. When two modules are tightly coupled they are said to be dependent on the other. Dependency causes one module to be modified when the other is modified.
If two modules have no interaction then they would have no relationship. This, however, is not relevant as it is only pertinent to realize coupling when it extends to coexisting entities. The coupling to be concerned with is that of two modules that interact. Good coupling is that of when two modules share data. Better cou-pling results from smaller pieces of data. In general, the smaller and less complex the data is, the looser the coupling.
The measure of how closely components are related is known as cohesion.
Cohesion, unlike coupling, is better the more of it that there is. There are several forms of cohesion: coincidental, logical, temporal, procedural, communicational, sequential and functional (Sommerville 2004). Modules should be loosely cou-pled, meaning they communicate by passing the most basic data available. Highly cohesive means that they should maintain as many forms of cohesion with the modules in the system.