CIS 3760: Software Engineering Supplemental Material: Mapping (UML) Models to (Java) Code
Instructor: Prof. Stacey Scott
School of Computer Science
University of Guelph https://www.uoguelph.ca/computing/people/stacey-scott stacey.scott@uoguelph.ca
© 2017-21 Stacey D. Scott
Common Forward Engineering Activities
• Forward Engineering
– Goal:Implementingtheobjectdesignmodelinaprogramming language
Mapping inheritance
Mapping associations
Composition vs. aggregation Run-time dependencies
CIS 3760
Software Engineering
2
Transformations b/w Model and Code Space
Model transformation
Model space
Source code space
System Model (in UML)
Reverse engineering
Another Program
CIS 3760
Software Engineering
3
Another System Model
Program (in Java)
Forward engineering
Refactoring
Common Forward Engineering Activities
• Forward Engineering
– Goal:Implementingtheobjectdesignmodelinaprogramming language
Mapping inheritance
Mapping associations
Composition vs. aggregation Run-time dependencies
CIS 3760
Software Engineering
4
Forward Engineering Example
Object design model before transformation:
-email:String
-maxNumLeagues:int +getMaxNumLeagues():int +setMaxNumLeagues(n:int)
+getEmail():String +setEmail(e:String) +notify(msg:String)
public class User {
private String email; public String getEmail() {
public class LeagueOwner extends User { private int maxNumLeagues;
public int getMaxNumLeagues() {
} }
CIS 3760
Software Engineering
5
return email; }
return maxNumLeagues; }
User
LeagueOwner
Source code after transformation:
Tphicet
public void setEmail(String e){ email = e;
public void setMaxNumLeagues(int n) {
}
public void notify(String msg) {
maxNumLeagues = n; }
// ….
}
Forward Engineering: Mapping a UML Model into Source Code
• Goal: We have a UML-Model with inheritance. We want to translate it into source code
• Question:Whichmechanismsintheprogramming language can be used?
• Common inheritance mechanisms in Java (other methods are available, but these are the most relevant for the design patterns we’ve learned in this course):
– Can“extend”aregular,fullydefinedclass;thisallows overwriting of methods (default in Java)
– Candefineand“extend”anAbstractclass – Can define and “implement” an Interface
CIS 3760
Software Engineering
6
Realizing Inheritance in Java
• Realization of specialization (i.e. top-down design of inheritance hierarchies) and generalization (i.e. bottom-up design of inheritance hierarchies)
– Definition of subclasses (children) or super class (parent)
– Java keyword: extends
• Realization of implementation inheritance (i.e. class inheritance, most basic form of inheritance, extending an applications’ functionality by reusing functionality in parent class)
– Extending an existing class, overwriting of methods
– No keyword necessary (to overwrite or define methods):
Overwriting of methods is default in Java
• Realization of specification inheritance (i.e. subtyping, inheriting from an abstract
class with all operations specified, but (at least some) not yet implemented)
– Specification of an interface/abstract class
– Java keywords: abstract, interface.
CIS 3760
Software Engineering
7
Example: Implementation Inheritance
public class Cat { string name; public Cat() {
} }
} }
CIS 3760
Software Engineering Source: https://syntaxdb.com/ref/java/inheritance
8
this.name = “Garfield”; }
public String sound(){ //implemented sound method from the interface return “Meow!”;
public class Tiger extends Cat { //the variable ‘name’ and the method ‘sound()’ are inherited public Tiger(){
super(); //calling the constructor in the super class, Cat }
@Override
public String sound(){ //overwriting the sound() method in Cat
return “Roar!”; }
// This method is only for demonstrative purposes and is bad practice (you shouldn’t override a // method and call super elsewhere)
public String catSound(){
return super.sound(); //will call the sound method from the Cat parent class
Ex. Specification Inheritance: Abstract Class
public abstract class Animal {
String name;
abstract String sound(); // all classes that implement Animal must
}
public class Cat extends Animal { public Cat() {
}
this.name = “Garfield”; }
// have a sound method
public String sound(){ //implemented sound method from the // abstract class & method
return “Meow!”; }
Note: Abstract classes and methods are declared with the ‘abstract’ keyword. Abstract classes can only be extended, and cannot be directly instantiated. Abstract classes provide a little more than interfaces. Interfaces do not include fields (variables) and super class methods that get inherited, whereas abstract classes do. This means that an abstract class is more closely related to a class which extends it, than an interface is to a class that implements it.
CIS 3760
Software Engineering Source: https://syntaxdb.com/ref/java/abstract
9
Ex. Specification Inheritance: Interface
public interface Country {
//all classes that implement Country must have the method getCapital() public String getCapital();
}
public class NACountry implements Country { String capitalCity;
public NACountry(String capitalCity) {
}
this.capitalCity = capitalCity; }
public String getCapital(){ // implemented method signature from the // interface
return capitalCity; }
Note: An interface only contains method signatures and constants, which means it contains no implementation code. All method signatures must be given implementation in any class that implements the interface.
CIS 3760
Software Engineering Source: https://syntaxdb.com/ref/java/abstract
10
Common Forward Engineering Activities
• Forward Engineering
– Goal:Implementingtheobjectdesignmodelinaprogramming language
Mapping inheritance Mapping associations
Composition vs. aggregation Run-time dependencies
CIS 3760
Software Engineering
11
Mapping Associations
1. Unidirectional one-to-one association 2. Bidirectional one-to-one association
3. Bidirectional one-to-many association 4. Bidirectional many-to-many association
11
CIS 3760
Software Engineering
12
11
1 **
*
Unidirectional one-to-one association
Object design model before transformation:
Advertiser 1 1
Account
Source code after transformation:
public class Advertiser {
private Account account;
} }
public Advertiser() {
account = new Account();
Note, the above unidirectional one-to-one association representation is a high-level design representation. At a lower level of design it could be specified as either composition or aggregation. The above code translation implements a composition relationship. This could also be implemented as an aggregation relationship by passing an Account object into the Advertiser class and assigning the “account” attribute to this passed in object.
CIS 3760
Software Engineering
13
}
CIS 3760 } Software Engineering
Bidirectional one-to-one association
Object design model before transformation:
Advertiser 1 1 Account
+ getAcount (): Account
+ getOwner (): Advertiser
Source code after transformation:
public class Advertiser { /* account is initialized
public class Account { /* owner is initialized
* in the constructor and never * modified. */
* in the constructor and
private Account account; public Advertiser(){
* never modified. */
private Advertiser owner;
public Account(Advertiser owner){
account = new Account(this); }}
public Account getAccount(){ public Advertiser getOwner(){
return account; }}
return owner;
this.owner = owner;
14
}
Software Engineering
Bidirectional one-to-many association
Object design model before transformation:
Advertiser 1 * Account
+ addAcount (a: Account)
+ removeAcount (a: Account)
+ setOwner (newOwner: Advertiser)
Source code after transformation:
public class Advertiser { private Set accounts; public Advertiser() {
public class Account {
private Advertiser owner;
public Account (Advertiser owner) {
accounts = new HashSet(); }
this.owner = owner; }
public void addAccount(Account a) { accounts.add(a);
public void setOwner(Advertiser newOwner) { this.owner = newOwner;
a.setOwner(this); }
} }
public void removeAccount(Account a) { accounts.remove(a);
a.setOwner(null); } CIS 3760
Note, the “accounts” attribute in Advertiser can be implemented as any type of collection data structure (e.g. Set (which is 15 unordered), ArrayList, etc.)
Bidirectional many-to-many association
Object design model before transformation
* {ordered} * Source code after transformation
Tournament
Player
*
+ addPlayer(p: Player)
+addTournament(t: Tournament)
public class Tournament { private List players; public Tournament() {
public class Player { private List tournaments; public Player() {
players = new ArrayList(); }}
tournaments = new ArrayList();
public void addPlayer(Player p) { if (!players.contains(p)) {
public void addTournament(Tournament t) { if (!tournaments.contains(t)) {
players.add(p);
tournaments.add(t); t.addPlayer(this);
p.addTournament(this); }}
}} }}
CIS 3760 Note, when {ordered} is specified, a suitable ordered data
Software Engineering
structure must be used to implement the collection of objects.16
Common Forward Engineering Activities
• Forward Engineering
– Goal:Implementingtheobjectdesignmodelinaprogramming language
Mapping inheritance
Mapping associations Composition vs. aggregation Run-time dependencies
CIS 3760
Software Engineering
17
Association vs. Aggregation vs. Composition
• Association denotes that there is some type of relationship between classes
• Aggregation is special type of Association, often referred to as a “uses” relationship
– https://www.uml- diagrams.org/aggregation.html
• Composition is special type of Aggregation, often referred to as a “has-a” or “owns” relationship
https://www.geeksforgeeks.org/association-composition-aggregation-java/
– https://www.uml- diagrams.org/composition.html
CIS 3760
Software Engineering
https://www.visual-paradigm.com/guide/uml-unified-modeling- language/uml-aggregation-vs-composition/
18
Mapping Aggregation to Code
Object design model before transformation:
Department 1…* 0…* Employee + addStaff (e: Employee)
+ removeStaff (e: Employee)
Source code after transformation:
in main code:
public class Department { private List
{…
Employee empl1 = new Employee(“Dara”); Department dept = new Department(); dept.addStaff(empl1);
}
CIS 3760
Software Engineering
staff = new List
… // do stuff }
public void addStaff(Employee empl) { staff.add(empl);
In an aggregation relationship, the class being “used” has an independent lifecycle from the using class. E.g. the object “empl1” will not be destroyed when the object “dept” is destroyed. We see this here because it is created OUTSIDE of dept and passed into the dept object. Often this happens as
a pass into the using class’s constructor method. 19
}
public void removeStaff(Employee empl) {
staff.remove(empl); }
Mapping Composition to Code
Object design model before transformation:
Car
1
1 Engine
Source code after transformation:
in main code:
public class Car {
private Engine engine; public Car() {
{…
Car myCar = new Car();
engine = new Engine(); }
… // do stuff }
…other stuff in class
} In a composition relationship, the class being “owned” has a dependent lifecycle from the owning class. E.g. the car’s engine (“engine”) will be
destroyed when the object “myCar” in the main code is destroyed. We see this here because it is created INSIDE of the myCar object. Often, we seen this creation in the constructor method, but it could also happen in another method called later.
CIS 3760
Software Engineering
20
Common Forward Engineering Activities
• Forward Engineering
– Goal:Implementingtheobjectdesignmodelinaprogramming language
Mapping inheritance Mapping associations Composition vs. aggregation Run-time dependencies
CIS 3760
Software Engineering
21
}
A run-time dependency is when a class uses an operation/method in another class or
Run-time dependency
Object design model before transformation:
}
Calculator
MathUtility
Source code after transformation:
public class Calculator { public Calculator() { }
class MathUtility {
public static Int StringToInt(String s) {
public Int AddStringInts(String s1, String s2) { return MathUtilities.StringToInt(s1) +
Int i;
// do some magic conversion return i;
MathUtilities.StringToInt(s2); …other stuff in class
} }
uses a member/variable in another class without instantiating an object of that class.
This is typically implemented as a call to a static member/variable or a static method
of the class being used. The above example shows a run-time dependency on the
CIS 3760
MathUtility class through the use of its StringToInt static method.
22
Software Engineering
Summary
• Strategy for implementing associations: – Beasuniformaspossible
– Individualdecisionforeachassociation
• Example of uniform implementation – 1-to-1association:
Role names are treated like attributes in the classes and translate to references
– 1-to-manyassociation:
“Ordered many” : Translate to List
“Unordered many”: Translate to Set, List, or any other “collection” data structure
CIS 3760
Software Engineering
23