Buscar

Essential Object Oriented Analy - Bala Paranj

Prévia do material em texto

Table of Contents
 
1. Introduction 
2. Domain Object 
3. Parts of Speech Technique 
4. Case Study : Buffet R Us 
5. How to Identify Services 
6. CRC Technique 
7. Interviewing Domain Experts 
8. Conceptual Category List 
9. Static Modeling 
10. Class Design 
11. Finding Operations from the Static Model 
12. Abstraction 
13. Choose Good Names 
14. Encapsulation 
15. Polymorphism 
16. Interfaces 
17. Domain Model 
18. Effective Use of Inheritance 
Object Oriented Analysis
This book covers the basics of Object Oriented Analysis. We will discuss
about domain objects, identifying services, classes, static modeling, finding
operations from the static model, parts of speech and CRC techniques. We
will apply the concepts to case studies to make the learning process easier.
About the Author
Bala Paranj has a Master's degree in Electrical Engineering from Wichita
State University. He began working in the IT industry in 1996. He started his
career as a Technical Support Engineer and then became a Web Developer
using Perl, Java and Ruby.
He is available for freelance work. Please contact him at support@zepho.com
or via Ruby Plus. He is also working on screencasts based on this book. If
you want notification about the release, please contact him.
https://www.rubyplus.com/contact
Domain Object
Domain object is an object that consist of domain information only, it usually
represents a logical entity in the problem domain.
How to Identify Domain Objects?
There are several techniques to identify domain objects and the services
provided by them. They are:
 
Parts of speech technique
CRC technique
Interviewing domain experts
Conceptual Category List / Common Associations List
Analysis Patterns [Fowler]
Analysis Patterns is beyond the scope of this book. In the upcoming chapters,
we will discuss the first four techniques in detail.
Parts of Speech Technique
In Abbot's linguistic analysis approach we identify the noun phrases and the
verbs in the problem description or system specification to find the classes
and their operations.
Verb extraction is used to find the methods. Identify the verbs in the problem
statement. These are good candidates for the actions that must be performed
by the classes to carry out its responsibilities.
Booch finds Abbott's method to be useful due to its simplicity and the fact
that it forces the developer to work in the vocabulary of the problem space.
The drawback is that the quality of the domain objects depends on the
informal specification document. Coad and Yourdan suggest looking for key
nouns and verbs in the widest possible variety of domain-related
documentation, not just developer-generated domain descriptions.
Example for Parts of Speech
Technique
Let us now see an example that illustrates the parts of speech technique for
finding the domain objects. Consider the following statement of requirements
for the first iteration of a Library System.
Books and Journals : The library contains books and journals. It may have
several copies of a given book. Some of the books are for short term loans
only. All other books may be borrowed by any library member for three
weeks. Members of the library can normally borrow up to six items at a time,
but members of staff may borrow up to twelve items at one time. Only
members of staff may borrow journals.
Borrowing : The system must keep track of when books and journals are
borrowed and returned, enforcing the rules described above.
Requirements statement with noun and noun phrases in bold is shown below.
Books and Journals : The library contains books and journals. It may have
several copies of a given book. Some of the books are for short term loans
only. All other books may be borrowed by any library member for three
weeks. Members of the library can normally borrow up to six items at a time,
but members of staff may borrow up to twelve items at one time. Only
members of staff may borrow journals.
Borrowing : The system must keep track of when books and journals are
borrowed and returned, enforcing the rules described above.
According to the Merriam-Webster dictionary, noun is something that is an
entity, quality, state, action or concept.
Books, Journals, copies of a book are all entity therefore they are nouns and
is in bold. Staff member and library member are noun phrases. Short term is
an adjective. Loan can be a noun as well as a transitive verb. Loan is a
concept in the above context. We don't have enough information about the
loan concept in the description. From the description, we can say "Book is
loaned to a library member". This will be modeled in the domain model as a
relationship between the Book and LibraryMember with loaned to as the
name of the association. Therefore we will eliminate it.
Here is a simple and easy way to find out if a given word is a noun or not. Go
to Webster and just type in the word, the dictionary shows the meaning of the
entry and also tells you if it is a noun or not.
http://www.merriam-webster.com
Case Study - Buffet R Us
Let's identify the domain objects for the following system.
Problem statement
We are required to develop a payment system for Buffets R Us. Buffets R Us
is a restaurant specializing in serving buffets to its customers. Lunch buffet is
priced at $ 9.59 per person and dinner buffet is priced at $ 14.79 per person.
Beverages are priced separately.
Buffets R Us advertises at a local movie theaters to build its customer base.
The customers can turn-in the used movie tickets for a 10% discount on their
order. A senior discount of 15% is available for people over the age of 55.
Only one discount is applicable at any one time. Kids less than five years old
eat free on Tuesdays.
Payment can be made using credit card, personal cheque or cash only. The
receipt contains the date and time stamp of the purchase, restaurant name,
name of each item and its price, discount type, discount amount, sales tax of
6.5% and the total amount for the purchase.
Answer
Lunch, Dinner, Payment, CreditCard, Cheque, Cash, Beverage are the set of
domain objects for this system. All of these objects represent concepts that
are part of the domain model of the payment system.
Examining the nouns in the problem statement can help discover candidate
domain objects, but not all nouns will relate directly to the system being
designed. Candidate objects that do not have attributes or behavior required
by the system are rejected. For example, “theaters” is a noun, but does not
have any behavior or attributes required by the system, so it is rejected. The
remaining objects are the core domain objects that will be part of the system.
How to Identify Services
Case Study - Automated Movie Ticket
System
This case study is used to illustrate how to identify services. We are
commissioned to develop an Automated Movie Ticket System (AMTS) for
Movie Brothers R Us. This system will allow the movie goers to browse for
the current showings that are playing Users can also search based on show
time, artist name or movie name. Users will buy tickets after selecting a
movie and a show time, and after inserting any valid discount coupon.
This system will only accept credit card as the payment method. Students can
insert their student discount coupons to receive a discount of 20%. Matinee
shows are priced at a 40% discount in order to fill up the empty seats.
Once the card is authorized, the system prints the movie tickets with the show
time, movie name, date & time and the theater screen number where the
movie is played. Identify the services provided by this AMTS system.
Answer
browse(), search(), buy(), pay(), charge(), print()
This is the complete list of all services to be provided by the SuD (system
under discussion).
Examining the verbs or verb phrases in the problem statement can help
discover candidate services that must be provided by the system, but not all
of them will relate directly to the system being designed. Candidate verbs or
verb phrases thatdo not describe behavior required by the system are
rejected. For example, “insert” is a verb, but it does not describe a behavior to
be implemented by the system.
The “matinee” shows get a discount and this is actually a temporal event; the
system does not need any input from the actor.
The verb “accept” is not a service to be provided by the system under
development. Accepting a credit card is not the service to be provided, the
desired service is to charge the credit card.
The verb “receive” is not a service to be provided by the system under
development. Receiving a discount is not the service to be provided.
Applying the discount is part of the pay service.
The verb “play” is not a service to be provided by the system under
development. Playing the movie is the responsibility of the theater, not the
system. It is out of scope.
CRC Technique
CRC technique can also be used to find the domain objects and services.
CRC stands for Class-Responsibility-Collaborator. Let's now see how to
identify objects using CRC Technique.
Responsibility-Driven Design is a technique that can be used to identify
objects. Responsibilities become attributes and operations after we refine our
model. This technique is very helpful to teach beginners about OOAD. Once
you become familiar with this approach it becomes easy to think in terms of
objects and collaborations. Consequently, developers will be able identify
objects mentally.
This can be used during both the analysis and design phases. The emphasis
will shift from what to how when we move from analysis to design. So, the
CRC cards will be different for these two phases.
In order to make it easier for the reader to understand the CRC technique, we
will use a mini-case study to illustrate the concepts. The emphasis will be on
identifying objects and we will make simplifying assumptions to make it
easier to swiftly move to implementation stage. This means we will not have
any realistic non-functional requirements, legacy constraints etc. Let's now
look at a case study.
Customer Credit Card Account
Management Program
System Description
The program facilitates a credit card customer service representative (CSR) to
maintain and access information about credit cards of the customer. Credit
card type, holder’s name, credit card number and expiration date describe
each credit card. Customer needs access to their credit card related
information such as account balance, available credit, last payment date, last
payment amount, any current minimum amount due, due date, past due
amount if any. Data is saved in XML format.
A CSR can run the program by logging on using their user id and password.
This is due to the need for knowing who made changes or notes on a
customer’s credit account. Notes are made to record notification of late
payment by the customer, request for credit line increase, report of lost or
stolen credit card, report of unauthorized charges, dispute related information
etc. Once the CSR logins into the system, they can pull up the customer
related information by entering the credit card number and doing search to
get the related information. The screen shows customer’s authentication
information such as their social security number, security question and
answer and date of birth. A CSR must authenticate the customer before
making any modifications or giving out any information related to that
particular customer account. Customer record includes their current address,
contact number and account holder name.
Let us now move on from the initial specification to writing main success
scenario for most frequently used use cases. We will defer the alternative
path related work to the next iteration. The interaction between the system
and the actor will be documented in a user interface intensive terms at a high
level of abstraction. This is because we will know what data is going into and
out of the system. This is a short-cut that we are taking for the purpose of our
case study. In reality the users and domain experts will provide input on what
information they will be providing and expecting from the system.
We have selected Record Dispute as the most frequently used use case
because we are making the assumption that the use cases that are most
frequently used are Retrieve type of use case and this information can be
given by the automated system over the phone. The phone interface is not
capable of handling dispute charges. Our program therefore will focus more
on functionality provided to the CSRs. CSR is capable of resolving the
dispute and in some cases provide immediate resolution in favor of the
customer depending on the situation.
Scenarios
Scenario 1 CSR selects “Record Dispute” from the menu.
High-level interaction
 
1. CSR selects “Record Dispute” from the menu.
2. System displays a new screen that can capture all the dispute related
information.
3. Customer provides the merchant name, transaction amount, transaction
date and the reason for dispute. CSR enters this information into the
system and saves it.
Scenario 2 : Customer wants to update address.
High-level interaction
 
1. CSR pulls up the account information related to the customer by
searching on the account number. The customer record contains social
security number, date of birth, current address and the security question
2. CSR requests the customer to identify himself and checks the
information with that of the system. CSR selects change address.
3. System prompts for new address.
4. CSR enters the new address and updates the system.
We will use the above two scenarios to illustrate the CRC technique.
Identifying Candidate Classes
Let us use parts of speech technique to find the candidate classes. Underline
the nouns and noun phrases in the specification document to get a list of
potential classes. Merriam-Webster dictionary defines noun as any member
of a class of words that typically can be combined with determiners to serve
as the subject of a verb, can be interpreted as singular or plural, can be
replaced with a pronoun, and refer to an entity, quality, state, action, or
concept
Step 1 - Identify candidate classes from specification document. The
candidate classes are in bold in the following specification document.
The program facilitates a credit card customer service representative
(CSR) to maintain and access information about credit cards of the customer.
Credit card type, holder’s name, credit card number and expiration date
describe each credit card. Customer needs access to their credit card related
information such as account balance, available credit, last payment date,
last payment amount, any current minimum amount due, due date, past
due amount if any. Data is saved in XML format.
A CSR can run the program by logging on using their user id and password.
This is due to the need for knowing who made changes or notes on a
customer’s credit account. Notes are made to record notification of late
payment by the customer, request for credit line increase, report of lost or
stolen credit card, report of unauthorized charges, dispute related information
etc. Once the CSR logins into the system, they can pull up the customer
related information by entering the credit card number and doing search to
get the related information. The screen shows customer’s authentication
information such as their social security number, security question and
answer and date of birth. A CSR must authenticate the customer before
making any modifications or giving out any information related to that
particular customer account. Customer record includes their current address,
contact number and account holder name.
Step 2 – Identify candidate classes from scenarios.
Parts of speech technique has the draw back of looking at only the
specification for the candidate classes. We will miss classes that will be
required for implementation if we do not look at other sources. Therefore let
us look for candidate classes in our scenarios as well.
Scenario 1: CSR selectsRecord Dispute from the menu.
High-level interaction:
 
1. CSR selects Record Dispute from the menu.
2. System displays a new screen that can capture all the dispute related
information.
3. Customer provides the merchant name, transaction amount, transaction
date and the reason for dispute. CSR enters this information into the
system and saves it.
Scenario 2: Customer wants to update address.
High-level interaction:
 
1. CSR pulls up the account information related to the customer by
searching on the account number. The customer record contains social
security number, date of birth, current address and the security
question
2. CSR requests the customer to identify himself and checks the
information with that of the system. CSR selects change address.
3. System prompts for new address.
4. CSR enters the new address and updates the system.
Step 3 – Create Candidate Class List
Candidate Classes
 
1. Credit card
2. Customer service representative
3. Customer
4. Credit Card type
5. Holder’s name
6. Credit card number
7. Expiration Date
8. Account Balance
9. Available Credit
10. Last Payment Date
11. Last payment amount
12. Current minimum amount due
13. Due date
14. Past due amount
15. User id
16. Password
17. Credit Account
18. Notes
19. Credit Line
20. Social Security Number
21. Security Question
22. Security Answer
23. Date of birth
24. Current Address
25. Contact Number
26. Account Holder Name
27. Record Dispute
28. Merchant Name
29. Transaction Amount
30. Transaction Date
31. Dispute Reason
32. Account Number
33. Account
34. New Address
We have combined the candidate classes from the specification and the
scenarios. We have also eliminated any duplicate entries in our list. Now we
are ready to move on to the next step, which is filtering the candidate classes
to find the final list of classes.
Step 4 – Triage the Candidate Classes
Let us now go through our selection of nouns and check if they can be moved
from a candidate class list to required class list.
 
Credit card. The Credit card consists of account holder’s name, credit
card number, expiration date and credit card type. We need this class for
implementation therefore we will move this to our class list.
Customer service representative. This is just an actor. Is this part of our
system? Does the system keep track of anything related to CSR? The
answer is yes, but only for the purposes of keeping track of who made
changes or added notes to a customer account. We will keep this class.
Customer. We maintain the customer information in the system. These
are cardholder’s name, current address, date of birth, social security
number and credit card number owned by the customer. We will
implement this as a class.
Credit Card type. This is just a String (Master Card, Visa, Amex,
Discover etc) and is an attribute that belongs to Credit card class that we
discovered above.
Holder’s name. This is the same as the Account Holder’s name listed
below.
Credit card number. This is a number that can be represented as an
Integer. It is an attribute that belongs to Credit Card class.
Expiration Date. This is a Date object and is an attribute that belongs to
Credit Card class.
Account Balance. This is a number and can be represented by a real
number. This is an attribute of Credit Account class (listed below in this
list).
Available Credit. A real number represent amount of credit available. It
is another attribute of Credit Account class.
Last Payment Date. A Date is an object and is an attribute of Last
Payment class. Last Payment will be a new class that will hold all the
information related to the previous statement.
Last payment amount. A real number and an attribute of Last Payment
class.
Current minimum amount due. A real number and an attribute of
Current Payment class (a new class to hold all the relevant attributes and
behavior).
Due date. A Date object and an attribute of Current Payment class.
Past due amount. A real number and an attribute of Current Payment &
Last Payment class.
User id. This is a String and is an attribute that belongs to Login
Account used by CSR to login to the system.
Password. Same as above.
Credit Account. This is an important concept and must be implemented
as a class. This will hold all the data and behavior associated with the
credit card account of the customer.
Notes. This is String object holding the information related to the
communication between the CSR and the customer. Unknown during
first pass on this list. After the first pass is made on this list we have
made a decision to let this be part of Record Dispute class (which is
below).
Credit Line. A real number that belongs to the Credit Account class
discovered above.
Social Security Number. A number that is an attribute of the Customer
class.
Security Question. A String that is an attribute of some class. We don’t
know what it will be yet. We might define a Authenticate or Identify
class.
Security Answer. Same as above.
Date of birth. A Date class and is an attribute of Customer class.
Current Address. This is a class by itself; we will implement a class
called Address that will have street name, zip, city and state attributes.
This is required due to the application requirements.
Contact Number. An Integer that is an attribute of Customer class.
Account Holder Name. A String that is an attribute of Credit Card class.
Record Dispute. This is a class that will have all the data and behavior
related to the dispute.
Merchant Name. A String that is an attribute of Record Dispute class.
Transaction Amount. A real number and an attribute of Record Dispute
class.
Transaction Date. A Date object and an attribute of Record Dispute
class.
Dispute Reason. A String that is an attribute of Record Dispute class.
Account Number. This is the same as the Credit Card Number. We will
combine the two names representing the same concept with just one
name, Credit Card Number. Therefore, this is eliminated.
Account. This concept is already captured by Credit Account. We will
eliminate this candidate class from the list.
New Address. This is the same type as Address that we have already
discovered. So, we don’t need a new class to implement this concept.
Step 5 – Required Class List
We now have the following list of classes that we need to design and
implement in our system.
 
Credit card
Customer service representative
Customer
Last Payment
Current Payment
Credit Account
Address
Record Dispute
Step 6 – List of Attributes Identified During the Triage of Candidate
Classes
 
Credit Card type. Credit card class
Credit card number. Credit Card class.
Expiration Date. Credit Card class.
Account Balance. Credit Account class
Available Credit. Credit Account class.
Last Payment Date. Last Payment class.
Last payment amount. Last Payment class.
Current minimum amount due. Current Payment class
Due date. Current Payment class.
Past due amount. Current Payment & Last Payment class.
User id. Login Account class.
Password. Login Account class.
Notes. Record Dispute class.
Credit Line. Credit Account class.
Social Security Number. Customer class.
Security Question. Authenticate or Identify class.
Security Answer. Same as above.
Date of birth. Customer class.
Contact Number. Customer class.
Account Holder Name. Credit Card class.
Merchant Name. Record Dispute class.
Transaction Amount. Record Dispute class.
Transaction Date. Record Dispute class.
Dispute Reason. Record Dispute class.
Step 7 – List of Attributes Categorized According to the Class where it
belongs
Credit Account
 
Account Balance
Available Credit
Credit Line
Last Payment
 
Last Payment Date
Last payment amount
Past due amount
Current Payment
 
Current minimum amount due
Due date
Past due amount
Login Account
 
User id
Password
Identify
 
Security Question
Security Answer
Credit Card
 
Account Holder Name
Expiration Date
Credit Card Number
Credit card type
Expiration Date
Record Dispute
 
Merchant Name
Transaction Amount
Transaction Date
Dispute Reason
Notes
Customer
 
Contact NumberDate of birth
Social Security Number
Step 8 – Identify Class Responsibilities
The functionality required by the system is described in the use cases. The
classes that collaborate together will implement the functionality and each
class will have some responsibilities that it carries out during this activity.
We can expand the high-level interactions into collaborations between classes
and document the responsibilities that emerge.
Each class will have a CRC card with the following information on it.
 
1. Class name
2. Attributes
3. Responsibilities
4. Collaborators
5. Short description of the purpose of the class
The short description is written on the back of the card. For instance for
Credit Card class, it will be: "I maintain all the information related to Credit
Card and provide any required operations on my data to my clients".
When you trace the use case scenarios with the CRC cards record all the
information indicated above. During the trace if you find that you need a new
class, we can create a new card for the new class and record the related
information on it.
Scenario 1: CSR selects Record Dispute from the menu.
High-level interaction:
 
1. CSR selects “Record Dispute” from the menu.
2. System displays a new screen that can capture all the dispute related
information.
3. Customer provides the merchant name, transaction amount, transaction
date and the reason for dispute. CSR enters this information into the
system and saves it.
Class-level interaction:
 
1. CSR select “Record Dispute” from the menu.
2. Record Dispute UI is displayed on the screen.
3. Record Dispute Controller saves the Credit Account and the
corresponding Record Dispute in the system.
As we work at a lower level of abstraction we find that we must associate an
account to a dispute. Otherwise we will not know which customer filed a
dispute. We also have discovered that we need a new class called Record
Dispute Controller. This class hooks up the UI to the domain classes Credit
Account and Record Dispute. Let us now document the responsibilities on
the CRC cards.
Class: Record Dispute Controller
Responsibilities:
 
To respond to the user-interface events.
To delegate work to the appropriate domain classes.
To display the results to the user.
Collaborators:
 
RecordDisputeUI
CreditAccount
RecordDispute
Back of the card:
Description: I am the use case controller responsible for connecting the user
interface to the domain classes. I encapsulate control logic.
Attributes: Let us leave this blank for now. We do not need to be exhaustive
while filling out the CRC card. We must avoid analysis paralysis.
CRC card format
Front of the CRC card
Back of the CRC card
You can think of a CRC card with the front as the public view and the back
as the private view with implementation details. The CRC should contain
Class name, Responsibilities and Collaborators section as the minimum.
Attributes are considered implementation details and must be shown on the
back of the card.
Class: Record Dispute
Responsibilities:
 
Create a dispute record in the system.
Provide access to existing dispute record.
Collaborators: Record Dispute UI
Description: I maintain all the information related to dispute and provide any
required operations on my data to my clients
Attributes:
 
Merchant Name
Transaction Amount
Transaction Date
Dispute Reason
Notes
Note: We can rename the RecordDispute to DisputeRecord (verb phrase is
changed to noun phrase due to the naming convention for classes).
Scenario 2: Customer wants to update address.
High-level interaction:
 
1. CSR pulls up the account information related to the customer by
searching on the account number. The customer record contains social
security number, date of birth, current address and the security question
2. CSR requests the customer to identify himself and checks the
information with that of the system. CSR selects change address.
3. System prompts for new address.
4. CSR enters the new address and updates the system.
Class-level interaction:
 
1. CSR enters account number of the customer and does a search for the
account.
2. Credit Account UI detects the user-interface search event and delegates
the search functionality to Credit Account Manager class.
3. Credit Account Manager searches to find the account information
corresponding to the account number of the customer.
4. Credit Account Manager returns the Credit Account class.
5. Credit Account UI queries the Credit Account class for the required
fields and displays the information.
6. CSR selects the change address from the menu.
7. Credit Account UI responds to the change address user-interface event
and prompts for new address.
8. CSR enters the new address and clicks update address. Credit Account
UI sends the new address data and delegates the update operation to the
Account Manager class.
9. Account Manager class updates the system with the new address.
Class: Credit Account UI
Responsibilities:
 
Provide the UI for the credit account related information.
Delegate work to the Credit Account Manager class.
Collaborators:
 
Credit Account Manager
Credit Account
Description: I provide the user interface to the credit account information
and delegate all the functionality to a controller class.
Attributes: none (for now)
Class: Credit Account Manager
Responsibilities:
 
1. Provide access to the existing credit account information.
2. Provide search by account number functionality to find credit account.
Collaborators:
 
Credit Account UI
Credit Account
Description: I encapsulate the control logic for searching and retrieve
account related data used by my clients.
Attributes: none (for now)
Class: Credit Account
Responsibilities:
 
Provide access to the credit account information.
Collaborators:
 
Credit Account Manager
Credit Account
Description: I provide the data and access to the credit account related
information to my clients.
Attributes:
 
Account Balance
Available Credit
Credit Line
We can repeat the procedure outlined above to all other scenarios. Once we
have a complete set of CRC cards documented we need to verify that each
class is capable of providing the functionality documented in the scenarios. If
we had missed any responsibility then we need to add them. If there are
responsibilities that are not required then it must be removed from the
classes.
The main advantage of the CRC cards is their flexibility. It is very easy to
move the CRC cards around to see how they collaborate and make changes to
the CRC cards. This is very much like Agile Modeling. This technique is
extremely useful during the analysis phase when the requirements are fluid.
During the design phase we can add more details to the CRC cards such as
define the data types of the attributes, include classes to satisfy non-
functional requirements etc. Keep in mind that we work with cards that are
limited in size and we may not prefer to work with CRC cards during the
design phase at all.
The real question is Where does the CRC technique fit in the big picture? The
answer is that they find their use in modeling the vocabulary of the system. In
other words, CRC cards in conjunction with use case-based analysis can aid
us in the discovery of abstractions in both the problem and the solution
domain. They are also used when we are modeling structural relationships.
By using CRC cards in combination with use case analysis we can identify
the classes that must interact. These interacting classes must have an
association between them. Larman calls this as need to know associations. It
is noteworthy to mention that CRC technique forces us to look at the
structural and behavioral scenarios. This concludes our simple introduction to
the CRC technique.
Interviewing Domain Experts
Domain objects can be identified by interviewing domain experts or from
requirements document. The domain objects can be categorized into
following three types:
 
1. Business objects that are things used in abusiness. These are
abstractions such as invoice, account etc.
2. Real-world objects or concepts that a system keeps track. E.g., Book,
Boat etc.
3. Events that occur such as gate closing, train arrival etc.
This technique can also be used to find the services provided by the objects.
Domain experts have very good knowledge in their domain. Interview
domain experts and use abstraction to identify classes and services. This
approach utilizes their domain expertise and is likely to result in a high
quality domain model.
Also this technique can be used in conjunction with other techniques to find
the missing domain objects and services. This will improve the quality of the
domain model. If this is the case then we get feedback from the domain
experts for the results we got from other techniques.
Major drawbacks include that it can result in analysis paralysis (how many
experts? what if they disagree?) and the inability to trace the abstractions
back to requirements.
Conceptual Category List
A conceptual category list [Larman] can be used to identify the domain
objects. In this technique we can use the list of categories as a crutch to
discover the domain objects. Study the requirements and determine items
from the problem that belongs to a certain category. This is also called as
Common Associations List.
Similarly common associations list can be used to identify the relationships
between the domain objects. Seek common relationship patterns in the
interactions between classes and objects and invent ways to use these
patterns. Evaluate the semantic relationships and seek to maximize coupling
among things that are semantically related while minimizing coupling among
things that are semantically distant and subject to change.
The disadvantage is that we may get stuck at some point when something
does not seem to fit well in the category list. In such a situation remember
that no there is no such thing as the perfect domain model. It is just more or
less valuable tool in understanding the domain. If we capture all the
important concepts and their relationships in the domain then we can get a
good domain model.
All of the above techniques can be combined to identify classes and services
depending on the situation, so that we optimally use the different approaches
based on their strengths to arrive at a good domain model.
Static Modeling
Identifying Attributes
To find the attributes of a class ask yourself the following questions:
 
What does the class know?
What information should be stored by the class?
We will discuss this in further detail below when we develop a domain
model.
Developing a Domain Model
For very small business domains, domain model is not required; a glossary of
terms will be sufficient. Domain model should only be concerned with the
problem domain and should not include anything related to solution domain.
The main purpose of the domain model is as a communication tool between
the developers and other non-technical staff. This is the reason why we do
not include anything related to the solution domain.
The sequence of activities shown in this eBook is for learning purposes only.
In real world, OOAD skills that you apply will not be rigid or follow a linear
structure.
Identify Classes
Class is a template that defines the structure and behavior of an object. It
defines the data (state) and methods (behavior) that all objects of that class
will possess.
An object is characterized by responsibilities, semantic integrity constraints,
types and relationships. Meriam Webster defines the term semantic as related
to meaning. An example of a semantic integrity constraint on a class called
Reservation would be Number of rooms reserved cannot be zero or negative.
These rules are the constraints on the data values of the object that impose the
business rules. From a programming standpoint, you must throw an exception
to indicate invalid data passed to the methods in a class. This prevents
violation of the data integrity in the system.
To identify classes, make a list of key nouns from use cases. These are
candidate classes. Synonyms must be merged into one term and documented.
Classes can be found by using the following categories:
 
1. Tangible things (e.g., Book, Apple, Credit card application form)
2. External systems (i.e., actors, e.g., Credit Bureau)
3. Devices the system interacts with (library card scanner, receipt printer)
4. Locations of things (Concert Hall, Exhibit Room)
5. Roles of people or systems (Teacher, Credit Authorizer)
6. Organizations (Hospital, Finance department)
7. Events (signing a lease or shifting a gear)
8. Remembered events (time of delivery of a package, date of signing a
lease)
Identify Attributes of a Class
Find the data that a class needs to maintain its state. The decision whether to
represent the data as an attribute or derive it when required depends on speed
vs space trade off. E.g., total debts owned to all creditors by a credit
counseling service customer.
Keep the data in the class where it is used most of the time. During the triage
on the candidate classes, eliminate any classes that provide the functions of a
primitive data type such as string etc. It becomes an attribute.
Identify methods
Make a list of all the verbs in the use cases. These become a list of probable
methods. Similar to the classes any synonyms must be merged into one term
and documented.
We have discussed about identifying responsibilities and attributes in the
requirements modeling chapter. This is during the analysis phase, therefore
each responsibility of a class may have to mapped on to several methods
when we design. The attributes that we found in that chapter are related to the
problem domain only.
Class Design
Following are the important concepts to know about class design:
 
Operations, parameters, attributes etc use the programming language
syntax that has been selected for implementation.
Visibility of attributes and operations are specified using the keywords
of the selected programming language (If it is Java; public, protected,
private are used)
The relationships between design classes have meaning when it is
implemented. Egs: Generalization becomes inheritance in the
programming language. Associations and aggregations often maps to
variables of classes in the implementation phase. This provides
references among objects.
A design class can represent an interface if the programming language
supports it.
A class interface is the list of operations that is provided by the class to its
clients.
Note: This is different from interface that specifies a contract that must be
implemented by a class when it extends (implements) the interface.
When we identify the operations the resulting set of operations may not be
sufficient for other applications. This is due to our use case driven
development process. Since our use cases are specific to the application
under development. It may not require certain operations that might be
required in other applications.
Use case driven approach results in minimal set of operations for a class. At
the end of the project, there can be a separate phase allocated for looking for
objects that can be reused. This topic is beyond the scope of the exam.
Before we discuss the various techniques to find operations, we must keep in
mind that the discovery of operations is done during the design phase.
Therefore, we must communicate with the stakeholders and ask them if they
need this functionality. If they had overlooked or could not foresee the need
this requirement then we need to update other artifacts such as use cases,
design class diagram and anything else that might be affected. If it is not
required then we can discard this operation. Of course no update would be
needed in that case.
Design of operations depends on the trade-off priorities dictated by the
requirements. Some of the factors involved during this trade-off are: memory
usage, efficiency, re-usability, maintainability etc.
From thespecification perspective the associations in the class diagram
represent the responsibilities of the participating classes. Following are the
types of operations that we have to consider during this activity.
 
1. Setting the value of an attribute.
2. Accessing the value of an attribute.
3. Checking the value of any derived attribute.
4. Creating relationships.
5. Querying an association.
6. Setting an association.
7. Accessing all objects that have contains relationship.
Setting Attribute Values
For each attribute in a class we must decide whether we need an operation
that sets the attribute’s value. This decision is based on whether we should
allow a client to change the attribute or not. For example, once we create an
order number during the purchase of an item in a restaurant, we should not
change it. Therefore, when the Order object is created, the order number is
initialized and we do not provide a method to set the order number. In UML
this constraint is called as frozen. An attribute which is frozen cannot change
its value during the lifetime of the object in which it is declared.
Consider the Guest class in Hotel Guest Management System. From now we
will use the abbreviation HGMS to refer to this system. The marketing
department is taking a survey to target its customer effectively. The result of
this survey produces customer profile. The profile consists of answers to
questions like their age, sex, number of children, income range etc. In this
example, the attribute sex cannot be changed and we do not define any setter
method for it. You might ask: What happens if a careless mistake was made?
This is assumed to be a rare case, if this happens then we have to delete the
object and create a new one with the correct attributes from the beginning.
Syntax:
void setAttribute(type : attribute); or
boolean setAttribute(type : attribute)
Accessing the Value of an Attribute
Attribute values are accessed by defining accessors. We must minimize the
getters. Because the class must operate on its data and provide services and
not act as a data holder. There are certain situations where a class can be a
data holder, ValueObject is an example in Java.
Checking Derived Attributes
If the value of an attribute is calculated from the values of other attributes in
the object then it is called as derived attribute. Therefore, we cannot set the
value of a derived attribute. It may be required to allow clients to access the
derived attributes. If so, we can define accessor for this purpose. For example
we can calculate the number of days over due on an invoice by operating on
the invoice due date. The value may either be calculated everytime it is
accessed or cached for faster retrieval. Decision must be made based on the
time vs space trade off requirements.
Creating Associations
Guest can stay in one room only. Either 0 or 2 guests can occupy room. Let
us now consider the scenario where the room is vacant. The HGMS needs
this object in order to set the value of the Boolean attribute isClean. After the
housekeeper has finished cleaning the room, the list is given to the front desk
clerk who updates the system using the user interface to indicate which
rooms are clean.
When a guest checks in to a room, the association between the Guest object
and Room object must be created. We will put an operation in the Room class
that allows us to set the guest name, namely, setGuestName(String : name).
For the purpose of illustrating the concept we will assume guest names are
unique. Later we will see how to model this without making this assumption
during our discussion on qualified association.
Sometimes, the associations will be created when we create the object. In the
example, when we create the Performance object we pass in the Dancer
object and Event object to the constructor. The constructor creates the
association between Dancer object and Event object. Association classes will
be discussed in detail later in this chapter.
Querying an Association
We can query an association for two different purposes. They are:
 
1. To check for the existence of an association.
2. To find out which object is associated for a given object.
Case 1: Checking to see if the relationship exists:
We can add an operation called isTeamMember() to the Dancer class to
check if the Dancer is on a team or not. But we will not know the name of the
team.
Case 2: Accessing the value of each association:
If we are interested in knowing the value of an association, we can query the
association to find out. We can add an operation getGuestName() to the
Room object. Given an object, the query tells us which object has an
association with it. If we want to query previous association then we can add
getPreviousGuestName(String : roomNumber). For example, this can allow
us to know which guest had forgotten their belongings.
A dancer can be a member of one or more teams. This model is shown from
history over time perspective. It means that a dancer can be part of a team
only one at a time but could possibly be a member of many teams over time.
Each team consists of at least 2 to at most 10 dancers.
We are not showing the possibility of a dancer not being a member of the
team (i.e., in 0..* notation, the case when 0 value is taken by the association)
because our application requirements dictate that a dancer has to be part of a
team in order to compete in the event.
Changing Associations
Case 1: Go through the associations one at a time and see if there is a need to
change the association to a different object. Add an operation to change the
association if necessary.
joinTeam() allows the Dancer object to join different teams. addDancer()
allows the Team object to add different Dancers.
Case 2: Check if an operation that deletes the association is required. This
operation is valid only if the multiplicity can take on the value of 0 (0 means
no association). Otherwise, the integrity of the artifacts will be lost.
quitTeam() allows the dancer to leave the team. dropDancer() allows the
dancer to be removed from the team.
Iteration over Associations
When you have a one to many association in the design class diagram, it
gives us a clue that clients may want to iterate over all the objects to do
something.
In this example, RoomScheduler object needs to iterate over all the rooms
and make a list of all rooms that are clean. Therefore we define a new
operation called isClean() in the Room object for this requirement.
Reference Objects and Value Objects
Objects have identity. This is much more important to reference objects than
it to value objects.
Reference objects are called so because you will get hold of that object
through a reference or pointer in the code. For example it could be a thing
like Invoice. The identity is important because of the constraint that there can
be only one object to designate an invoice in the real world. All variables that
point to this invoice will reference the same invoice object. This means any
changes to a particular Invoice object will be seen by all the variables
pointing to it.
In order to check if two references to an Invoice is the same you have to
compare their identities. If this object is cloned for some reason then we have
to synchronize the changes.
In simple terms the Value objects are objects that represent constants. Once
they are created they cannot be changed. So they are immutable. We could
have many value objects that represent the same object in the real world. For
example a Date object that has a value of 21-July-05. We could have an
application where two different person might have that date as their birth
date. If we had two copies of this particular date object then they can be
interchanged. The date object is created when required and destroyed when it
is no longer needed.
In order to check if two dates are the same you must compare their values. So
an equality test method must be implemented. In this case the method will
compare the values of year, monthand day for both the objects. The
implementation of this method depends on knowing what data must be same
for two objects to be the same.
Let us look at another example where we have a BreadCrumb object that
represents the bread crumb of an user's navigation through a web site. In this
case, the BreadCrumb object must compare the hyper links of the two
BreadCrumb objects to determine if they are the same. The BreadCrumb
object is a custom data type and is an example of how you can extend the
type system with your own classes.
Value objects are immutable therefore we do not provide any setters. Of
course there are always exceptions to any rule. So, if you are using a
persistence framework like Hibernate and you want to persist a value object,
you could provide a private setter. Each value object is a separate object but
sharing is allowed since it will not lead to any bugs in the software due to
accidental updates. If you want another date with a different value then
instead of updating the existing date object you must create another date
object with the required values. This will prevent update of a date object that
belongs to some other object leading to bugs in the software.
If frozen is applied to a class it means that all attributes and association ends
corresponding to that class can never change. There is a difference between
frozen attribute and a read-only attribute. Read-only means the client code
cannot change the value and it may change value due to the implementation
inside the class. For example the attribute legalDrinkingAge can be frozen to
a value of 21 and this can never change whereas the age attribute can be read-
only but it cannot be frozen because it changes with passage of time.
If a new law is passed and the legal age for drinking is changed then it can be
changed only by the implementing class and not the client code. As far as the
client is concerned the attribute legalDrinkingAge is frozen. The same
argument holds if an inadvertant mistake is made in setting the initial value of
this variable.
If a class has a mutable object as one of its attribute and we have a setter due
to the requirements then the implementation of the setter must clone the
mutable object and return it. This will prevent any of the clients accessing the
mutable object from accidentally changing its value and introducting bugs in
the code.
Let us look at an example to illustrate this concept. Consider a Reservation
object which has check in and check out date as its mutable attributes. There
is a semantic constraint imposed by the application requirements that once
the guest checks in at a particular date the check in date cannot be changed.
The client code can call the getter of the check in date and once it gets the
date object it can change its value by calling the setter in the Date object. This
will become a bug because it violates the constraint. So eventhough you do
not provide a setter for the check in date in the Reservation object the setter
in the Date object allows the value to be changed. Since the getter for check
in date returns the reference for the check in date object the client code can
use this reference to change the value of the check in date. To prevent this
bug we must clone the check in date object and return it. Client code can
access this value maybe to generate reports but it will not be able to change
its value.
Abstraction
In this chapter, you will learn how to determine when a new class is needed.
To quote Booch in Object-Oriented Analysis and Design with Applications:
An abstraction denotes the essential characteristics of an object that
distinguish it from all other kinds of objects and thus provide crisply
defined conceptual boundaries, relative to the perspective of the viewer.
The term perspective of the viewer needs an explanation. Let us consider a
House object, when a banker sees this house, he thinks in terms of the value
of the property, opportunity for appreciation, etc whereas when a decorator
views it, he thinks in terms of what color the house should be painted, total
area to be painted, etc. The same object House can be viewed from different
perspectives and can lead to entirely different abstractions by different
people.
Booch, Fairsmith, Henderson-Sellers define abstraction as:
Any model that includes the most important, essential, or distinguishing
aspects of something while suppressing or ignoring less important,
immaterial, or diversionary details.
Coad, Fairsmith, Henderson-Sellers, Rumbaugh define abstraction as:
The cognitive tool for rationalizing the world by considering only those
details necessary for the current purpose".
So, abstraction is about what details we choose to emphasize and what details
we choose to ignore. What we choose to emphasize is dictated by the
application. It simplifies the things that we look at in the real world. For
example, a chair can be made up of different kinds of material, height
adjusting knobs, reclining adjustment knobs etc. If every time we looked at
the chair, if we had to deal with what material it is made up of, how the
height adjustment knobs are designed and other irrelevant details related to
our purpose using a chair to sit, our brains will be exhausted. So, the
abstraction process simplifies things and allows us to manage complexity
during problem solving process.
Interface of a Class and its Role in Abstraction
The interface of a class should offer a set of methods that belong together.
Let us consider a class that represents Ticket. It would contain data
describing the ticket, date of event, name of the event, seat number, and so
on. It would offer services to initialize and use ticket. Here is the code
showing how it looks.
public class Ticket {
 public String seatID;
 public Date eventDate;
 public String eventName;
 public Ticket(String seatID, Date event Date, String eventName) {...}
 public String getSeatID() {}
 public Date getEventDate{}
 public String getEventName{}
}
The ticket object cannot be modified after it is created because the values of
the attribute cannot be changed. The interface of the class has methods that
provide access to the attributes that are relevant to the abstraction that the
Ticket object represents. This class might have additional methods and data
to support these services but the clients using this class don't need to know
about these implementation details. For example, the seatID could be
accessed from a relational database. This is an example of a well defined
interface with good abstraction because every method in the interface is
focused on expressing a single concept.
Conversely, an example for a class with poor cohesion would be a class
called MegaBitePizzaAndAutoService which consists of unrelated methods
such as deliveryTotal(), dineInTotal(), oilChangeTotal() etc. To correct the
mistake all operations related to auto service can be moved to a new class
called AutoService. The public methods are the basis for evaluating class
abstraction. This does not mean that methods private to the class can have
poor abstraction. The private methods should also be designed with good
abstraction in mind.
Guidelines for Creating Class Interfaces
Guideline 1: Each class should implement one and only
one abstraction.
If a class implements more than one abstraction or if we cannot determine
what abstraction the class implements, then the class must be split into one or
more well defined abstraction.
The following example shows a class with inconsistent interface. It is
inconsistent because level of abstraction is not uniform.
public class DanceTeam extends ArrayList {
 public void addDancer(Dancer aDancer) {...};
 public void removeDancer(Dancer aDancer) {...} ;
 public Dancer getFirstItem() {...};
 public Dancer getLastItem() {...};
 public Dancer getNextItemInList () {...};
}
Java Example of a Class Interface with Mixed Levels of Abstraction
The abstraction of the first two methods is atthe "Dancer" level. The
abstraction of the last three methods is at the "List" level. The DanceTeam
class is capturing two abstraction: a dancer and a Collection utility. The
ArrayList class is a utility class found in the Java's java.util package. The fact
that we have chosen a particular collection class to implement the
functionality should be hidden from clients. This gives us the flexibility of
changing the implementation where we could use a different collection utility
class which for example gives us better performance under multi-threaded
environment.
The following code shows the class after it has been refactored to improve its
abstraction.
public class DanceTeam {
 public void addDancer(Dancer aDancer) {...};
 public void removeDancer(Dancer aDancer) {...};
 public Dancer getFirstDancer() {...};
 public Dancer getLastDancer() {...};
 public Dancer getNextDancer() {...};
 private Collection dancerList; <----- Collection class now is hidden.
}
In the code shown above, the abstraction of all the methods is at the "Dancer"
level. We now have the variable that is of type Collection interface. We could
implement the dancerList as ArrayList, Vector or any other type of collection
class. It is actually a design flaw for the DanceTeam to inherit from the
ArrayList class. It fails the inheritance test question: Is DanceTeam a type of
ArrayList?
If the abstraction of the DanceTeam object requires searching and sorting
then it should be made explicit by making it part of the class interface.
Guideline 2: Have a clear understanding of the
abstraction.
Sometimes there might be two classes representing two similar abstractions.
Choosing the right class depends on clear understanding of the abstraction it
represents.
During development if two classes are very similar then having a clear
understanding of the abstraction will help us to come up with the correct
interface for the class. Data dictionary helps us to clarify our understanding.
Guideline 3: Refactor unrelated information to a new
class.
If you find that roughly half of the methods work with half of the class's data
and the other half of methods work with the remaining other half of the data
then you actually have two classes combined into one. Split the class into two
separate classes. This leads us to the rule: Most of the methods defined for a
class should be using most of its attributes most of the time.
Guideline 4: Analyze classes that has more than
approximately 7 attributes.
It has been discovered that 7 + 2 is the number of things an individual can
remember while performing other tasks. If a class exceeds the 7 + 2 limit then
check if the class can be decomposed into multiple smaller classes. If the
attributes are primitive data types like integers and strings then you set the
limit as 9, if it is complex objects then the limit is 7.
List of Reasons to Create a New Class
The following list shows good reasons to create a new class:
 
1. Create a class to represent each real-world object. This object
must be within the scope of the system that we are modeling.
2. Create a class to model abstract objects. Abstract object is not
concrete real-world object. It provides an abstraction of other
concrete objects. For example, Chips and Fruits really exist in
the real world whereas Food is an abstraction of other specific
foods. If I ask you to point me to a food, you only point to a
specific type of food such as apple, orange etc.
So if you consider a Food abstract class and various sub-classes such as
Cake, Orange etc. There can be no instance of Food class. It is abstract. We
are modeling the real world and abstraction is one way by which we deal
with complexity. We can only create instances of the sub-classes Cake,
Orange etc. These instances will be named birthDayCake, anniversaryCake
etc. The sub-classes are concrete and you can create instances.
 
1. Create a class to reduce complexity. This is the most important
reason to create a class. Java Server Faces API is a good
example. JSF API has made it simple to write GUI code for
server based applications by hiding implementation details
such as communication related details from the client and
server.
2. Create a class to isolate complexity. For instance if we have to
deal with complicated algorithms, it will be easier to locate
and fix bugs if it is localized within a class. It will also be
easier to replace algorithms.
3. Create a class to minimize the impact of changes. Separate the
areas that are most likely to change. Our aim is to reduce the
number of classes that has to be modified when changes occur.
4. Analyze parameter passing to check if a new class is required.
Minimize passing data to several objects. This will require
reorganizing the class structure. If a parameter is being passed
to many methods it may be time to refactor so that the
parameter becomes the attribute of the new class and all the
methods which used it as a parameter now becomes the
interface of the new class. The method now can access the
attributes declared within the new class instead of receiving it
as a parameter.
5. Create new class to centralize control of tasks. You might be
accessing a directory server, database or other external source
of data. Creating a class that is responsible for the external
data access makes it easier to make changes.
6. Create a new class to enable re-use. We might refactor
existing classes so that it could be re-used in a different
application. The classes that are easy to design for re-use are
utility classes such as Collection classes, JNDI connection
pooling classes etc. User interface related classes can also be
easily designed for re-use if we architect the system to use an
architectural pattern like MVC.
7. Create a new class to represent one abstraction. A class that
represents multiple abstractions should be split into multiple
classes until each one represents a single abstraction. Keep
related data and behavior in one place. Two classes related by
a one-to-one relationship can be combined to form a single
class only when it results in a single abstraction. Spin off non-
related information within a single class into another class.
8. A data item needs additional data or behavior. A data item
contained in a class that requires additional behavior or
additional data of its own should be made into its own class.
9. An array contains certain elements that mean different things.
Each element of the array should become a field in a new
class. This eliminates the need for conventions about the
meaning of each array element. Each field can be named
appropriately for its purpose.
10. A class has a numeric type code that does not affect its
behavior. A numeric type code that does not affect a class's
behavior should be made into its own class so that the
compiler can do type checking on it. This has an advantage
over numbers because you can ensure that only valid codes
can be constructed, reducing bugs. [Fowler - Refactoring ]
11. When we find that a class has two different definitions during
OO analysis, split the class into two different classes having
different names. Each class should represent a single
abstraction. If the class has two different definitions, it is
really two abstractions given a common name. Each
abstraction should be given a different name and made a
separate class. These definitions will be included in the
Glossary.
Choose Good Names
In this chapter, we will discuss about choosing good names for classes and
methods
Choose Good Names for Classes
The name of the class should clearly indicate the abstraction represented by
the class. Noun is used to name classes. It should begin with an uppercase
letter. The names can be as long as required to make it understandable. For
example Ticket is a good class name where Tick is a bad class name for a
class that is representing the ticket abstraction. A class that has a name which
contains the data structure that it uses internally as part of the nameis also a
bad naming convention. Because it is exposing the implementation details
and violates encapsulation.
It is a good idea to name a subclass as Xsuperclass where X denotes the
specialization this class implements. For example, if the superclass is
ClubMember, a good name for a class that represents the specific type of
ClubMember in a club for golfers would be GolfClubMember. This helps
developers to quickly know where in the inheritance hierarchy we can find
this class.
For classes in the domain layer, choose names that correspond to real world
entities. This will allow us to directly map the analysis class to classes in the
design model thereby resulting in low semantic gap between the domain
model and the design model. This makes communicating the design clear.
When we encounter the same definition for two classes during the OO
analysis, we need to settle on a common name for the object. The name
should be chosen from the real world entities in the problem domain. This
will allow us to directly map the analysis class to classes in the design model
thereby resulting in low semantic gap between the domain model and the
design model. So, we can resolve this conflict by choosing the class name
that is close to the problem domain.
Choose Good Names for Methods
The name of the methods should explicitly tell the reader what it does. It
should be meaningful and clear. It should start with a verb. The names can be
as long as required to make it understandable. Since the methods are invoked
using a class name, part of the name is already available. For example,
instead of author.getAuthorBookList(), it is better to have
author.getBookList(). If a function returns a value then name the function for
the returned value. For example ticket.isAvailable() is a good method name.
The question is available? returns a boolean value.
When a class has opposite operations, name them explictly instead of using
obscure names. Example: addDancer(), removeDancer().
Consistent Abstractions
You can look at concepts at several different levels of details. For example let
us consider a "Seat" object from a flight reservation system. When you
consider the seat in a aircraft, you might be interested in attributes of the seat
such as its number, whether it is window or aisle type, and its comfort level
such as first class or coach class.
public class Seat {
 public String number;
 public String location;
 public String type;
 public Seat(String number, String location, String type) {
 initialize all parameters here...
 }
 public String getNumber() { ... }
 public String getType() {... }
 public String getLocation() {...}
}
As a side note, Seat object is immutable because its attributes cannot be
changed after it is created. We provide only getters (or accessor) and do not
provide settors (or mutator) in the Seat class.
If you are considering an abstraction that is about collection of seats as
described below then you are viewing the problem domain space at a
different level of abstraction.
public class Seats {
 public int totalSeats;
 public int availableSeats;
 public int reservedSeats;
 public boolean isSeatAvailable () {...}
 ....
}
The name of the class representing the abstraction described above should
actually be named something that reflects the abstraction it is capturing.
Therefore instead of Seats we can call it Seating or SeatAllocation. As a side
note, this object falls under the abstract noun concept in the conceptual class
category list.
Encapsulation
In this chapter, we will discuss about how to maintain encapsulation of
attributes and visibility of operations effectively.
All attributes should be hidden inside a class. As always, there are exceptions
to any rule, in this case it is very rare for an attribute to be declared public.
The only way for clients to access the attributes within a class is via methods.
If clients access the attribute very often then we should re-consider the
decision to declare the attribute within the class. Why does someone need it?
Is it possible to perform the required operation on the data by the class
owning it and provide the service to the clients? If this is possible then we
also need to ensure that the operation logically is related to the abstraction
that the class represents. Otherwise, move the data to another class and define
a new method that operates on it. This increases the cohesion of the class,
which is desirable.
What is Encapsulation?
Encapsulation is achieved by means of information hiding. Information
hiding means hiding of all the implementation details of a class from other
classes. Data is hidden from the clients and and it can only be accessed
through a well defined interface. The interface is well defined in the sense
that the interface defined is stable and hides the design decisions that are
likely to change. As long as the method does not change its signature and
fulfills its contract, the implementation of internal details can change without
affecting classes using the method. By doing this we hide the internal data
representation as well as the internal complexities of an implementation.
It is closely related to abstraction because encapsulation is the process of
hiding the details of an object that do not contribute to its essential
characteristics.
The goal is to eliminate the changes propagating to other classes when
changes are made to the class. This isolates the changes to just one class
avoiding global changes which makes maintenance easier.
Encapsulation prevents accidental updates. Allowing direct access to internal
data of a class permits any class to change it. Encapsulating the data by
allowing access only through methods allows rules to be applied to attempts
to change data and prevents accidental updates to invalid or unexpected
values. To prevent this, we could return read-only copy of the internal data
when a collection class is accessed. The client is not aware whether it is
getting a copy or the actual data. This decision is hidden from the client.
It allows re-use of abstraction without depending on the implementation.
Hiding the internal implementation of a class allows an abstraction to be
implemented in different ways without affecting the classes that use that
abstraction. Classes only depend on the abstraction that has published a stable
interface and is not wired to a specific class that implements the abstraction.
In other words we program to the interface not the implementation.
Encapsulation also provides opportunities to find simpler and elegant design.
This makes code easier to understand. It permits team members to work
independently on state and functionality and allows classes to be understood
in isolation.
Since encapsulation hides variable that are internal to an algorithm, allowing
access to variable only through public methods, the Project Manager can use
encapsulation to deal with the complexities during the early stages of the
project and avoid a maintenance nightmare during later stages of the product
life cycle. The Project Manager can make sure that stable interfaces are
defined between the different layers of the system in the beginning of the
project. This will avoid problems integrating the different layers and enforces
consistency in the interaction between layers.
People disagree on the distinction between encapsulation and information
hiding. Arguing that encapsulation means bundling of the data and methods
together into the same class. This may not necessarily hide the data from
external view. From the exam perspective, keep this in mind and use the
elimination process to answer any ambiguous questions on encapsulation.
Visibility
One of the primary task during class design is making decisions about which
methods should be made public and which must be made private. This is
called as visibility. For example, a class might implement 10 methods and
expose only 4 of them, the remaining 6 methods are used internally by the
class.Visibility concept differs with languages. So let us briefly discuss some of the
visibility concepts that are applicable to Java.
Public elements are visible to any class; private elements are visible only to
the owning class and protected elements are visible only to the subclasses.
In UML, attributes or operations can have a visibility indicator. The meaning
of the marker is language dependent. So we could have + (public), - (private),
and # (protected) for Java.
Encapsulation of Attributes
A class might use several attributes that cannot be accessed. In this case, the
attribute is declared private to the class and no accessor method is provided
for other classes to access. During design make the visibility of the attribute
as strict as possible i.e., private.
Always avoid making an attribute public. An attribute which is declared
public violates the encapsulation principle. For example, a Book class with a
public int edition declared within the class will make clients free to modify it
even without the Book class knowing that it has been changed. However, a
Book class that exposes:
public int getEdition() {...};
public void setEdition(int edition) {...};
has good encapsulation. The clients do not know whether the implementation
uses integer to store the edition or Book is storing the edition as string and
converting it to integer. For instance, due to performance / space trade off
decisions, it could be implemented differently.
This leads us to the rules:
 
Do not change the state of an object without going through its public
interface.
Classes should depend only on the public interfaces of other classes.
Semantic Violation of Encapsulation
It is easy to avoid syntactic violation of encapsulation by declaring the
internal methods and data private. Some examples of semantic violation of
encapsulation are: Failure to call database.connect() before calling
author.retrieve(database) because you know that the author.retrieve() method
will establish a new connection to the database in the absence of a database
connection. Not calling done() method in class A because you now that
performLastOperation() method in class A has already called it. Using class
B's MAXIMUM_POINTS constant instead of class A.MAXIMUM_POINTS
because you know they have the same value. Ignoring to call class A's init()
method because you know that class A's executeFirstOperation() method
automatically calls it. All of the examples above makes the client code
dependent on the private implementation of a class. One of the main theme of
the Design Patterns [GoF] book is that developers should program to an
interface. This means we should avoid looking at the implementation of a
class to program. When the code is dependent on the implementation,
encapsulation is broken and this makes the client code brittle since it has to
change whenever modifications to the implementation are made.
Inheritance and Encapsulation
An element that is coupled to another has a dependency on that other
element. If the other element changes, the dependent element may also need
to change. A well-designed superclass is not coupled to its subclasses, but a
subclass is inextricably tied to its superclass.
If a super class declares attributes that are visible only to its sub-classes, (in
Java we use protected keyword) it results in coupling between them. So, from
a strict point of view, Inheritance violates encapsulation. Do not allow the
subclasses to access the protected attributes directly. This will avoid
maintenance nightmare when the attributes are changed in the super class. At
the other extreme you can declare the attributes as private in the superclass,
this means the subclasses will not inherit the attributes. When the derived
class needs access to the private attribute declared in the base class provide a
protected method that can be used by the sub classes for that purpose.
Changes to the superclass, visible outside that class, are automatically
inherited by the subclass without having to change the code of the subclass.
All design decisions require human judgement that solves the problem at
hand. You have to weigh the advantages vs. disadvantages for your specific
situation before deciding either to follow this rule or not. In this case, some of
the things that you may look at are : How many sub-classes are we likely to
extend from this super-class? How many attributes require visibility in the
sub-classes? Answering these questions will help you to make the trade-offs
between different designs. You could also start with the simplest design that
will work for your current requirements and refactor the design in each
iteration.
If you are using inheritance and the derived class needs access to the private
attribute declared in the base class then provide a protected method that can
be used by the sub classes for that purpose.
Arguments and Encapsulation
A properly encapsulated class prevents its clients from knowing the
implementation details. All the public methods defined in a class is called as
the interface of a class.
The interface of a class should hide as much implementation details as
possible. Therefore, the number of arguments in the interface must be
minimal. Because more the number of arguments, the more the clients know
about how the class is implementing the functionality behind the signature of
the method.
Visibility of Operations
At the class level this means minimizing the number of methods that are
public and available for clients to use. This raises the level of abstraction of
the services provided by the class to the correct level. Do not clutter the
public interface of a class with methods that users of that class are either not
able to use or are not interested in using. Implement a minimal public
interface that all classes understand. You can minimize the public interface
by following the rule : Do not put implementation details such as common-
code private functions into the public interface of a class.
Let us look at an example for information hiding. Consider a website
dedicated to independent publishers. The system needs to allow profile to be
created for the authors. One of the data provided by the author is their age.
The system stores the age attribute in a class called Author. After a year
elapses the profile still shows the same age and the author has not aged at all!
By the way this is how Yahoo Profile is implemented.
The management now realizes that it is a mistake and wants to provide an
operation to calculate age of a given author. The problem is that code has
author.age in several different places (direct access to the public age
attribute). Now the code has to be modified to author.getAge() and
recompiled after the getAge() is implemented. This may not be a critical issue
in this system but if it was a retirement fund account which allows
withdrawal of money only after a certain age is reached by the member then
it is definitely a critical issue. This leads to the rule: All data should be hidden
(private) within its class.
Information hiding is useful for not only attributes and operations but also for
class design and sub system design. Let us look at different type of
information hiding example for an attribute. In MyTicketCo system the
maximum number of tickets that can be purchased is 50. Therefore do not use
50 in the code, instead define a constant MAXIMUM_TICKETS to hide the
information in one place. This makes it easy to change since it is found in
only one place.
This leads to the rule: Always use named constants instead of using
literals.
Encapsulation at System Level
In subsystem design we minimize the number of classes exposed to the
clients to provide a minimal interface. If this is not possible we use a Facade
[GoF].
Coupling and its Relation to
Encapsulation
Coupling is a quality metric used to describe amount of interconnection
between classes as well as between methods. It is basically a measure of
amount of encapsulation. Coupling is applicable to both

Continue navegando