Drawing a Design Diagram
using the Business Object Notation (BON)
EECS3311 A: Software Design Fall 2019
CHEN-WEI WANG
Classes:
Detailed View vs. Compact View (1)
●
●
shows a selection of: ○ features (queries and/or commands)
Detailed view
○ contracts (class invariant and feature pre-post-conditions)
○ Use the detailed view if readers of your design diagram should
know such details of a class.
e.g., Classes critical to your design or implementation
○ Use the compact view if readers should not be bothered with such details of a class.
e.g., Minor “helper” classes of your design or implementation e.g., Library classes (e.g., ARRAY, LINKED LIST, HASH TABLE)
Compact view
shows only the class name.
3 of 25
Why a Design Diagram?
● SOURCE CODE is not an appropriate form for communication.
● Use a DESIGN DIAGRAM showing selective sets of important: ○ clusters (i.e., packages)
○ classes
○ architectural relations [ generic vs. non-generic ]
○ features (queries and commands) [ client-supplier vs. inheritance ]
[ deferred vs. effective ]
[ deferred vs. effective vs. redefined ]
○ contracts
● Your design diagram is called an abstraction of your system:
[ precondition vs. postcondition vs. class invariant ]
○ Being selective on what to show, filtering out irrelevant details ○ Presenting contractual specification in a mathematical form
(e.g., ∀ instead of across . . . all . . . end). 2 of 25
Classes:
Detailed View vs. Compact View (2)
Detailed View
FOO
feature — { A, B, C }
— features exported to classes A, B, and C
feature — { NONE } — private features
invariant
inv_1: 0 < balance < 1,000,000
Compact View
FOO
4 of 25
Contracts: Mathematical vs. Programming
5 of 25
symbols (e.g., across ... all ..., across ... some ..., <=).
○ When presenting the detailed view of a class, you should include contracts of features which you judge as important.
○ Consider an array-based linear container: ARRAYED_CONTAINER+
feature -- Queries count+: INTEGER
-- Number of items stored in the container
feature -- Commands
assign_at+ (i: INTEGER; s: STRING)
-- Change the value at position 'i' to 's'. require
valid_index: 1 ≤ i ≤ count ensure
size_unchanged: imp.count = (old imp.twin).count
item_assigned: imp[i] ~ s
others_unchanged: ∀j : 1 ≤ j ≤ imp.count : j ≠ i ⇒imp[j] ~ (old imp.twin) [j]
feature -- { NONE } imp+: ARRAY[STRING]
-- Implementation of an arrayed-container invariant
consistency: imp.count = count
● Atagshouldbeincludedforeachcontract.
● Usemathematicalsymbols(e.g.,∀,∃,≤)insteadofprogramming
Deferred vs. Effective
means unimplemented (≈ abstract in Java) means implemented
Deferred
Effective
7 of 25
Classes: Generic vs. Non-Generic
● A class is generic if it declares at least one type parameters. ○ Collection classes are generic: ARRAY[G], HASH TABLE[G, H], etc.
○ Type parameter(s) of a class may or may not be instantiated:
HASH_TABLE[G, H] HASH_TABLE[STRING, INTEGER] HASH_TABLE[PERSON, INTEGER]
○ If necessary, present a generic class in the detailed form:
DATABASE[G]
feature
-- some public features here feature -- { NONE }
-- imp: ARRAY[G] invariant
-- some class invariant here
DATABASE[STRING]
feature
-- some public features here feature -- { NONE }
-- imp: ARRAY[STRING] invariant
-- some class invariant here
DATABASE[PERSON]
feature
-- some public features here feature -- { NONE }
-- imp: ARRAY[PERSON] invariant
-- some class invariant here
● A class is non-generic if it declares no type parameters. 6 of 25
Classes: Deferred vs. Effective
● A deferred class has at least one feature unimplemented. ○ A deferred class may only be used as a static type (for
declaration), but cannot be used as a dynamic type.
○ e.g., By declaring list: LIST[INTEGER] (where LIST is a
deferred class), it is invalid to write:
● create list.make
● create {LIST[INTEGER]} list.make
● An effective class has all features implemented.
○ An effective class may be used as both static and dynamic types. ○ e.g., By declaring list: LIST[INTEGER], it is valid to write:
● create {LINKED LIST[INTEGER]} list.make ● create {ARRAYED LIST[INTEGER]} list.make
where LINKED LIST and ARRAYED LIST are both effective descendants of LIST.
8 of 25
Features: Deferred, Effective, Redefined (1)
A deferred feature is declared with its header only (i.e., name, parameters, return type).
○ The word “deferred” means a descendant class would later implement this feature.
○ The resident class of the deferred feature must also be deferred.
deferred class
DATABASE[G] feature -- Queries
search (g: G): BOOLEAN
-- Does item ‘g‘ exist in database?
deferred end
end
9 of 25
Features: Deferred, Effective, Redefined (3)
● A redefined feature re-implements some inherited effective feature.
● A descendant class may still later re-implement this feature. 11 of 25
class
DATABASE_V2[G] inherit
DATABASE_V1[G] feature -- Queries
search (g: G): BOOLEAN
-- Perform a binary search on the database.
deferred end
end
Features: Deferred, Effective, Redefined (2)
● An effective feature implements some inherited deferred feature.
● A descendant class may still later re-implement this feature. 10 of 25
class
DATABASE_V1[G] inherit
DATABASE
feature -- Queries search (g: G): BOOLEAN
-- Perform a linear search on the database.
deferred end
end
Classes: Deferred vs. Effective (2.1)
Append a star * to the name of a deferred class or feature. Append a plus + to the name of an effective class or feature. Append two pluses ++ to the name of a redefined feature.
● Deferred or effective classes may be in the compact form:
LIST[G]*
LIST[LIST[PERSON]]*
DATABASE[G]*
LINKED_LIST[G]+
LINKED_LIST[INTEGER]+
DATABASE_V1[G]+
ARRAYED_LIST[G]+
ARRAYED_LIST[G]+
DATABASE_V2[G]+
12 of 25
Classes: Deferred vs. Effective (2.2)
Append a star * to the name of a deferred class or feature. Append a plus + to the name of an effective class or feature. Append two pluses ++ to the name of a redefined feature.
● Deferred or effective classes may be in the detailed form: DATABASE[G]* DATABASE_V1[G]+ DATABASE_V2[G]+
feature {NONE} -- Implementation data: ARRAY[G]
feature -- Commands add_item* (g: G)
-- Add new item `g` into database.
require
non_existing_item: ¬ exists (g) ensure
size_incremented: count = old count + 1 item_added: exists (g)
feature -- Queries count+: INTEGER
-- Number of items stored in database
ensure
correct_result: Result = data.count
exists* (g: G): BOOLEAN
-- Does item `g` exist in database?
ensure
correct_result: Result = (∃i : 1 ≤ i ≤ count : data[i] ~ g)
13 of 25
feature {NONE} -- Implementation data: ARRAY[G]
feature -- Commands add_item+ (g: G)
-- Append new item `g` into end of `data`. feature -- Queries
count+: INTEGER
-- Number of items stored in database
exists+ (g: G): BOOLEAN
-- Perform a linear search on `data` array.
feature {NONE} -- Implementation data: ARRAY[G]
feature -- Commands add_item++ (g: G)
-- Insert new item `g` into the right slot of `data`. feature -- Queries
count+: INTEGER
-- Number of items stored in database
exists++ (g: G): BOOLEAN
-- Perform a binary search on `data` array.
invariant
sorted_data: ∀i : 1 ≤ i < count : data[i] < data[i + 1]
Class Relations: Inheritance (2)
More examples (emphasizing different aspects of DATABASE): Inheritance Hierarchy Features being (Re-)Implemented
DATABASE[G]*
DATABASE_V1[G]+
DATABASE_V2[G]+
DATABASE[G]* feature {NONE} -- Implementation
data: ARRAY[G]
feature -- Commands add_item* (g: G)
-- Add new item `g` into database.
require
non_existing_item: ¬ exists (g) ensure
size_incremented: count = old count + 1 item_added: exists (g)
feature -- Queries count+: INTEGER
-- Number of items stored in database
ensure
correct_result: Result = data.count
exists* (g: G): BOOLEAN
-- Does item `g` exist in database?
ensure
correct_result: Result = (∃i : 1 ≤ i ≤ count : data[i] ~ g)
DATABASE_V1[G]+
DATABASE_V2[G]+ feature {NONE} -- Implementation
data: ARRAY[G]
feature -- Commands add_item++ (g: G)
-- Insert new item `g` into the right slot of `data`.
feature -- Queries count+: INTEGER
-- Number of items stored in database
exists++ (g: G): BOOLEAN
-- Perform a binary search on `data` array.
invariant
sorted_data: ∀i : 1 ≤ i < count : data[i] < data[i + 1]
15 of 25
Class Relations: Inheritance (1)
● An inheritance hierarchy is formed using red arrows. ○ Arrow’s origin indicates the child/descendant class.
○ Arrow’s destination indicates the parent/ancestor class. ● You may choose to present each class in an inheritance
hierarchy in either the detailed form or the compact form: *
LIST[G]
MY_LIST_INTERFACE[G]*
feature
-- some public features here feature -- { NONE }
-- some implementation features here
invariant
-- some class invariant here
++ MY_LIST_IMP_ONE[G]+ MY_LIST_IMP_TWO[G]+
14 of 25
Class Relations: Client-Supplier (1)
● A exists between two classes:
one (the client) uses the service of another (the supplier).
● Programmatically, there is CS relation if in class CLIENT there
client-supplier (CS) relation
is a variable declaration .
○ A variable may be an attribute, a parameter, or a local variable.
s1: SUPPLIER
● A green arrow is drawn between the two classes.
○ Arrow’s origin indicates the client class.
○ Arrow’s destination indicates the supplier class.
○ Above the label there should be a label indicating the supplier
name (i.e., variable name).
○ In the case where supplier is an attribute, indicate after the label
name if it is deferred (*), effective (+), or redefined (++). 16 of 25
Class Relations: Client-Supplier (2.1)
class DATABASE
feature {NONE} -- implementation
data: ARRAY[STRING] feature -- Commands
add_name (nn: STRING)
-- Add name ‘nn‘ to database.
require ... do ... ensure ... end
name_exists (n: STRING): BOOLEAN
-- Does name ‘n‘ exist in database?
require ... local
u: UTILITIES
do ... ensure ... end
invariant
...
end
class UTILITIES feature -- Queries
search (a: ARRAY[STRING]; n: STRING): BOOLEAN -- Does name ‘n‘ exist in array ‘a‘?
require ... do ... ensure ... end end
○ Attribute indicates two suppliers: STRING and ARRAY.
data: ARRAY[STRING]
○ Parameters nn and n may have an arrow with label , pointing to the STRING class.
○ Local variable u may have an arrow with label , pointing to the 17 of 25UTILITIES class.
nn, n
u
Class Relations: Client-Supplier (2.2.2)
If ARRAY is to be emphasized, label is .
The supplier’s name should be complete: ARRAY[STRING]
data
DATABASE+
feature
add_name+ (nn: STRING)
-- Add name `nn` into database. require
...
ensure
...
name_exists+ (n: STRING): BOOLEAN -- Does name `n` exist?
require
...
ensure
...
invariant
...
19 of 25
data+
n, nn
u
+ ARRAY[STRING]
+ STRING
+ UTILITIES
Class Relations: Client-Supplier (2.2.1)
If STRING is to be emphasized, label is , where . . . denotes the supplier class STRING being pointed to.
18 of 25
DATABASE+
feature
add_name+ (nn: STRING)
-- Add name `nn` into database. require
...
ensure
...
name_exists+ (n: STRING): BOOLEAN -- Does name `n` exist?
require
...
ensure
...
invariant
...
data+: ARRAY[...]
u
n, nn
data: ARRAY[...]
+ STRING
UTILITIES+
feature
search+ (a: ARRAY[STRING]; n: STRING): BOOLEAN
-- Does name `n` exist in array `a`? require
...
ensure
...
Class Relations: Client-Supplier (3.1)
Known: The deferred class LIST has two effective
descendants ARRAY LIST and LINKED LIST). ● DESIGN ONE:
● DESIGN TWO:
Question: Which design is better? [ DESIGN TWO ]
Rationale: Program to the interface, not the implementation. 20 of 25
class DATABASE_V1
feature {NONE} -- implementation
imp: ARRAYED_LIST[PERSON]
... -- more features and contracts end
class DATABASE_V2
feature {NONE} -- implementation
imp: LIST[PERSON]
... -- more features and contracts end
Class Relations: Client-Supplier (3.2.1)
We may focus on the PERSON supplier class, which may not help judge which design is better.
DATABASE_V1+
feature
-- some public features here feature -- { NONE }
-- some implementation features here
invariant
-- some class invariant here
DATABASE_V2+
feature
-- some public features here feature -- { NONE }
-- some implementation features here
invariant
-- some class invariant here
21 of 25
imp+: ARRAYED_LIST[...]
imp+: LIST[...]
+ PERSON
+ PERSON
Clusters: Grouping Classes
Use clusters to group classes into logical units. model
DATABASE[G]*
DATABASE_V1[G]+
DATABASE[G]+
feature -- Commands add_item++ (g: G)
tests
db
DATABASE_TESTS+
* LIST[G]
-- Insert new item `g` into the right slot of `data`. imp
base-library
feature -- Queries count+: INTEGER
-- Number of items stored in database
exists++ (g: G): BOOLEAN
-- Perform a binary search on `data` array.
invariant
sorted_data: ∀i : 1 ≤ i < count : data[i] < data[i + 1]
23 of 25
++ ARRAYED_LIST[G] LINKED_LIST[G]
Class Relations: Client-Supplier (3.2.2)
Alternatively, we may focus on the LIST supplier class, which in this case helps us judge which design is better.
DATABASE_V1+
feature imp+ -- some public features here
feature -- { NONE }
-- some implementation features here
invariant
-- some class invariant here
DATABASE_V2+
feature imp+ -- some public features here
feature -- { NONE }
-- some implementation features here
invariant
-- some class invariant here
* ARRAYED_LIST[PERSON]
* LIST[PERSON]
++ ARRAYED_LIST[PERSON] LINKED_LIST[PERSON]
22 of 25
Index (1)
Why a Design Diagram?
Classes:
Detailed View vs. Compact View (1) Classes:
Detailed View vs. Compact View (2) Contracts: Mathematical vs. Programming Classes: Generic vs. Non-Generic Deferred vs. Effective
Classes: Deferred vs. Effective
Features: Deferred, Effective, Redefined (1) Features: Deferred, Effective, Redefined (2) Features: Deferred, Effective, Redefined (3) Classes: Deferred vs. Effective (2.1)
Classes: Deferred vs. Effective (2.2)
24 of 25
Index (2)
Class Relations: Inheritance (1)
Class Relations: Inheritance (2)
Class Relations: Client-Supplier (1) Class Relations: Client-Supplier (2.1) Class Relations: Client-Supplier (2.2.1) Class Relations: Client-Supplier (2.2.2) Class Relations: Client-Supplier (3.1) Class Relations: Client-Supplier (3.2.1) Class Relations: Client-Supplier (3.2.2)
Clusters: Grouping Classes
25 of 25