530 likes | 910 Views
Software Engineering, CPSC-4360-01, CPSC-5360-01, Lecture 9. Review of Last Lecture. Design Patterns: Abstraction-Occurrence General-Hierarchy Composite Façade Player-Role State Singleton Observer. Overview of This Lecture. Basic Implementation Steps.
E N D
Software Engineering, CPSC-4360-01, CPSC-5360-01, Lecture 9 CPSC-4360-01, CPSC-5360-01, Lecture 9
Review of Last Lecture • Design Patterns: • Abstraction-Occurrence • General-Hierarchy • Composite • Façade • Player-Role • State • Singleton • Observer CPSC-4360-01, CPSC-5360-01, Lecture 9
Overview of This Lecture • Basic Implementation Steps. • Implementing Classes: • Class Association: • Navigation direction; • Multiplicity constraint; • Qualified associations; • Association classes. CPSC-4360-01, CPSC-5360-01, Lecture 9
Requirement Analysis Design Implement Test Where are we now? • Translate Design into Code CPSC-4360-01, CPSC-5360-01, Lecture 9
Implementation: Overview • Inputs: • Detailed Class Diagram; • Interaction Diagram; • Statechart. • Activities: • Implementation of class diagram; • Reminder: • Interaction diagrams show the basic behavior of some of the operations. • A statechart describes a complete lifetime for classes with complex behavior (next lecture – statecharts implementation). CPSC-4360-01, CPSC-5360-01, Lecture 9
Basic Steps in Implementation • Define method interface: • Give a formal/informal description of the functionality of an operation; • Useful in reducing misunderstanding; • Allows splitting the workload. • Decide the order of implementation: • Which class/subsystem to start. • Implement the design using a suitable programming language. CPSC-4360-01, CPSC-5360-01, Lecture 9
Defining Method Interface • During design: • Detailed information about the method header are defined: • Returned Type, Parameter Type; • Accessibility. • However, the functionality is not formally defined: • What should the method do? • What are acceptable values for the parameter? • Etc… • Even more important for complicated operations. CPSC-4360-01, CPSC-5360-01, Lecture 9
Operation Contract • Writing the operation contract is one possible way to define the functionality. • Define the precondition: • Express the constraint regarding the attributes of the class and the actual parameter. • Define the postcondition: • Express the effect of an operation: • Instance Creation/Deletion; • Attribute Modification; • Association Formed/Broken. • Description can scale in formality. CPSC-4360-01, CPSC-5360-01, Lecture 9
+deposit( amt : float )+withdraw( amt: float ) BankAccount -balance Operation withdraw()Contract: Example Precondition: - amt > 0 - amt <= balancePostcondition: - New balance = Old balance - amt CPSC-4360-01, CPSC-5360-01, Lecture 9
Order of Implementation • Many classes with dependencies in the design: • Need an order of implementation. • Two basic strategies: • Top-Down: • Starts with high-level components. • Then continue to implement the dependent components. • Bottom-Up: • Starts with the lower level classes, i.e., classes with least dependency. • Then proceed to code classes that make use of the implemented classes. CPSC-4360-01, CPSC-5360-01, Lecture 9
Example • myB may be an attribute in class A of class B; • The navigability is one possible indicator of the dependency. A myB B methodA() methodB() { myB.methodB();} A B A depends on B, i.e., Amakes use of B CPSC-4360-01, CPSC-5360-01, Lecture 9
Top Down Implementation • Starts with Class A, then Class B. • Advantages: • Class A represents a higher level component as it makes use of other classes. • Starting with high level components enables early validation of the overall system. • Disadvantages: • Need temporary implementation (known as stub) for lower classes. • Example: • A temporary implementation of methodB()is needed for the implementation of methodA(). CPSC-4360-01, CPSC-5360-01, Lecture 9
Bottom Up Implementation • Starts with Class B, then Class A. • Advantages: • Low level classes can usually stand alone. • No need for stub. • Disadvantages: • Have to postpone the generation of a complete executable program. CPSC-4360-01, CPSC-5360-01, Lecture 9
Class Diagram Implementation CPSC-4360-01, CPSC-5360-01, Lecture 9
Implementing Classes • Basic mapping: • A UML Class is implemented by a class in Java, C++, etc; • Attributes are implemented by fields; • Operations are implemented by methods. • There may be some language specific issues: • E.g., the implementation of abstract classes, interfaces, and generalization. CPSC-4360-01, CPSC-5360-01, Lecture 9
# # + + + Example: The Booking Class public abstract class Booking { protected int covers; protected Date date; protected Booking(int c, Date d) { covers = c; date = d; } public void setCovers(int c) { covers = c; } public Date getDate() { return date; } public void setArrivalTime(Time t) { } } The getCovers(c:Integer) operation should be setCovers(c:Integer). CPSC-4360-01, CPSC-5360-01, Lecture 9
Example: Generalization public class WalkIn extends Booking { public WalkIn(...) { ... } } public class Reservation extends Booking { Time arrivalTime ; public Reservation(...) { ... } public void setArrivalTime(Time t) { arrivalTime = t ; } } The setArrivalTime() operation should be setArrivalTime(Time t). CPSC-4360-01, CPSC-5360-01, Lecture 9
Implementing Associations • Associations (Class Diagram) describe properties of links (Object Diagram). Account Guarantor :Account :Guarantor • A link gives one object access to another and enables message passing. • Java: References (C++: Object Pointer) share these properties, so associations can be implemented with references. • References support only one direction of navigation. • Should restrict navigability to make implementation easier. • References should not be manipulated explicitly by other classes. CPSC-4360-01, CPSC-5360-01, Lecture 9
Optional Unidirectional Association • Distinction between associations: • direction; • multiplicity. • Reference variables can hold: • a reference to another object; • or the null reference. • So the ‘default’ multiplicity of a reference is ‘0..1’. CPSC-4360-01, CPSC-5360-01, Lecture 9
Implementation • The association is defined by a field in the Account Java class holding a reference to an instance of the DebitCard Java class: • public class Account { • private DebitCard theCard ; • ... • } Good match for simple object reference. 0..1 Account DebitCard CPSC-4360-01, CPSC-5360-01, Lecture 9
Maintaining the Association • As only Accountis “aware” of this association, it should also maintain the association: • Setup/Removal of the link; • Appropriate methods for accessing the linked object. e.g. public DebitCard getCard(){return theCard; } Return the linked object to outsider public void setCard(DebitCard card){ theCard = card; } Changing the linked object CPSC-4360-01, CPSC-5360-01, Lecture 9
Mutability for Association • The last example assumes that the DebitCardassociation is mutable: • An Accountobject can be linked to a different DebitCardobject during its lifetime. • Hence, it makes sense to have the following methods for setup/removal the link: public void setCard(DebitCard card){ theCard = card; } public void removeCard( ) { theCard = null; } CPSC-4360-01, CPSC-5360-01, Lecture 9
{Immutable} Immutable Association • Some associations are immutable: • once assigned, a link must not be altered. • The designer can state this in the class diagram: • The programmer has to check the link’s existence explicitly: public void setCard(DebitCard card) { if (theCard != null) { // throw ImmutableAssociationException } theCard = card ; } Explicit Check to maintain Immutable link CPSC-4360-01, CPSC-5360-01, Lecture 9
Compulsory Association • Multiplicity with lowerbound larger than 0 is compulsory, i.e., “At all times, the link(s) cannot be null”. • Example: • The above means “An Accountobject must have exactly one link to a Guarantorobject at all times”. • Programmers have to check explicitly to ensure this is true. CPSC-4360-01, CPSC-5360-01, Lecture 9
Implementation • The earliest possible opportunity to setup the link is in the constructor method: public Account(Guarantor g) { if (g == null) { // throw NullLinkError } theGuarantor = g ; } Make sure we have a guarantor • If the association is mutable, similar checks must be performed in methods that changes the link, e.g.: public setGuarantor(Guarantor g) { if (g == null) { // throw NullLinkError } theGuarantor = g ; } Make sure we have a guarantor CPSC-4360-01, CPSC-5360-01, Lecture 9
1-to-Many Unidirectional Association • Some associations require more than one link to be stored: • Data structures, such as arrays and vectors, can be used to store the references. • For a specific upper bound, e.g., “0…8”, specific checks must be implemented: public class Manager { private Vector theAccounts ; public void addAccount(Account acc) { theAccounts.addElement(acc) ; } } Stores * Accounts references. CPSC-4360-01, CPSC-5360-01, Lecture 9
Account DebitCard Account DebitCard theCard theAccount theCard: DebitCard theAccount: Account Bidirectional Association • Some associations need to be navigated in both directions: • because references are unidirectional, it will take two references to implement a bidirectional link; • the association can be implemented by including a suitable field in each of the associated classes. Bidirectional Association stated in Class Diagram Closest implementation of the Class Diagram in Java or C++ CPSC-4360-01, CPSC-5360-01, Lecture 9
Bidirectional Association Implementation • DebitCardis optional (“0..1” from Account). • Accountis compulsory (“1” from DebitCard). • Hence, the best way to satisfy the conditions is: • Create the Accountfirst, then the DebitCard: • { • Account acc1 = new Account() ; • DebitCard aCard = new DebitCard(acc1) ; • acc1.setCard(aCard) ;} Question: Why is that the order of associations creation to satisfy the conditions? CPSC-4360-01, CPSC-5360-01, Lecture 9
theCard acc2: Account aCard: DebitCard acc1: Account theAccount Referential Integrity • The bidirectional association is implemented as two separate references, it is important to keep them consistent. • The links should be “inversed” one to each other. • Known as referential integrity. • Example of referential integrity violation: • Account acc1 = new Account() ; • Account acc2 = new Account() ; • DebitCard aCard = new DebitCard(acc1); • acc2.setCard(aCard) ; The two links do not correspond to a valid bidirectional association! CPSC-4360-01, CPSC-5360-01, Lecture 9
Maintaining Referential Integrity • The problem with the example code on slide 29: • DebitCardcreation and reference setup (setCard() method) are two separate operations. • Responsibility of programmer to make sure the two operations are performed in a consistent fashion. • To minimize the human error, delegate one of the classes to maintain the referential integrity instead. • Example: • public class Account { • private DebitCard theCard ; • public void addCard() { • theCard = new DebitCard(this); • } • // other methods as well • } Accountclass handles both the DebitCardcreation and reference setting. CPSC-4360-01, CPSC-5360-01, Lecture 9
Joint Creation of Objects • Suppose an association is intended to be immutable and also needs to be traversed in both directions. • Constructors of both classes should take in an instance of the other to satisfy the constraint specified by the class diagram. • Java and C++ do not allow simultaneous object creation. • Must create one of the objects with the default constructor, i.e., to violate the constraint for a short time. CPSC-4360-01, CPSC-5360-01, Lecture 9
Code Example • Attempts to satisfy the compulsory link: Account a = new Account(g) ; Guarantor g = new Guarantor(a) ; g is not initialized. Account a = new Account(new Guarantor(a)) ; Guarantor g = a.getGuarantor( ) ; a is not initialized. • Have to violate the constraint for a while: gis initialized by default constructor, no Accountreference. Guarantor g = new Guarantor( ) ; Account a = new Account(g) ;g.setAccount(a) ; Setup the reference after Accountais properly initialized. CPSC-4360-01, CPSC-5360-01, Lecture 9
Domain Model Implementing Bidirectional Association myG Account Guarantor myG: Guarantor myA myA: Account Some likely methods getMyG( ): GuarantorsetMyG( Guarantor ) getMyA ( ): AccountsetMyA ( Account ) Class Diagram CPSC-4360-01, CPSC-5360-01, Lecture 9
Maintaining Bidirectional Association Methods that change the reference should maintain referential integrity. Take setMyG() for example: Have to set the reversed link too. If Accounthasalready a Guarantor: Either do not allow the link change. OR, remove the link with previous Guarantor. a :Account oldG: Guarantor The Reverse link has to be removed too. newG: Guarantor a.setMyG(newG) CPSC-4360-01, CPSC-5360-01, Lecture 9
Code Example //Class Account public void setMyG(Guarantor newG) { if (newG == null) //throw NullLinkError if (myG != null && myG != newG) { //previous Guarantor exists myG.removeMyA(this); } if (myG == newG) return; myG = newG; //set the reverse link myG.setMyA(this); } //Class Guarantorvoid removeMyA(Account a) { //only allows holder of //the reverse link call //this method if (a == myA) myA = null; } CPSC-4360-01, CPSC-5360-01, Lecture 9
Code Example (Cont) //Class Guarantor public void setMyA(Account newA) { if (newA == null) //throw NullLinkError if (myA != null && myA != newA) { //previous Guarantor exists myA.RemoveMyG(this); } if (myA == newA) return; myA = newA; //set the reverse link myA.setMyG(this); } //Class Accountvoid RemoveMyG(Guarantor g) { //only allows holder of //the reverse link call //this method if (g == myG) myG = null; } CPSC-4360-01, CPSC-5360-01, Lecture 9
Observations • Even with the complicated code, there are still some problems: • The old guarantor will be without an Accountobject. • Mutual recursive functions: • setMyA calls setMyG, which calls setMyA. • Very easy to get into infinite loop. • Should avoid compulsory bidirectional association if possible. • If bidirectional association must be used, immutability is recommended to curb the coding complexity. CPSC-4360-01, CPSC-5360-01, Lecture 9
One-to-Many Association • Raise no new issues: • Customer holds a collection of references. • Account holds a non-null reference. • Customer is a better choice as the “maintainer” for the referential integrity: • It provides a method like addAccount() that creates a new account and setup the reference. • Similar to the addCard() method on slide 30. CPSC-4360-01, CPSC-5360-01, Lecture 9
Many-to-Many Association • Previously discussed implementation techniques can be used. • Recommendation: • Allows only one of the classes to modify the links. • E.g., It makes sense to allow only the Customerto change links to Accountsand maintain the reversed link also. • Simplify the implementation as the coding logic can be considered from one direction only. CPSC-4360-01, CPSC-5360-01, Lecture 9
Many-to-Many Association • Another implementation technique is to reify the association: • The new class (e.g., Signatoryin the example above) is in a good position to maintain referential integrity. :Account :Signatory :Customer CPSC-4360-01, CPSC-5360-01, Lecture 9
Qualified Association • The purpose of a qualifier is often to provide efficient access to linked objects: • For example, to access accounts given only the account number; • Also to avoid a linear search through all accounts. CPSC-4360-01, CPSC-5360-01, Lecture 9
Implementing Qualifier • The run-time structure involves some kind of index to accounts: Using accno as index. CPSC-4360-01, CPSC-5360-01, Lecture 9
Code Example • Hash Table is a good choice to implement the index: public class Bank{ private HashTable theAccounts; public void addAccount (Account a) { theAccounts.put(new Integer(a.getNumber()), a); } public void removeAccount(int number) { theAccounts.remove(new Integer(number)); } public Account lookupAccount(int number) { return (Account) theAccounts.get(new Integer(number)); } } put (Object Key, Object Value) get(Object Key): Object CPSC-4360-01, CPSC-5360-01, Lecture 9
Hash table - reminder • It means a data structure that associates keys with values. • The primary operation it supports efficiently is a lookup: given a key (e.g., a person's name), find the corresponding value (e.g., that person's telephone number). • It works by transforming the key using a hash function into a hash, a number that is used to index into an array to locate the desired location ("bucket") where the values should be. CPSC-4360-01, CPSC-5360-01, Lecture 9
Hash table - reminder • Like arrays, hash tables provide constant-time O(1) lookup on average, regardless of the number of items in the table. CPSC-4360-01, CPSC-5360-01, Lecture 9
Association Class • Common strategy: • Transform the association class into a simple class; replacing it by two associations. CPSC-4360-01, CPSC-5360-01, Lecture 9
Module Student 1 * * Module Student :Module :Student :Module :Student Registration :Registration Registration :Registration :Registration :Registration Mark = 76 Mark: Integer Mark = 89 Mark: Integer Mark = 76 Mark = 89 :Student :Student Implementing Association Class Class Diagram Class Diagram Object Diagram Object Diagram CPSC-4360-01, CPSC-5360-01, Lecture 9
Code Example public class Module { private Vector registrations; public void enrol(Student st) { registrations.addElement( new Registration(st) ); } ... } Maintain the link to Registration Pass the Student to Registration. class Registration { private Student student; private int mark; Registration(Student st) { student = st; mark = 0; } ... } Registration keeps track of the Student reference. CPSC-4360-01, CPSC-5360-01, Lecture 9
Requirement Analysis Design Implement Test Where are we now? • Class diagram implementation CPSC-4360-01, CPSC-5360-01, Lecture 9
Summary • Basic Implementation Steps • Implementing Class: • Class Association: • Navigation direction • Multiplicity constraint • Qualified associations • Association classes CPSC-4360-01, CPSC-5360-01, Lecture 9