420 likes | 474 Views
Learn how to convert UML classes to Java, map associations, handle multiplicity, implement inheritance, and more. Understand aggregation, composition, and persistence layers for effective Java development.
E N D
Converting UML classes to Java • Item • name : String • + getPrice() : int price • Map association to attribute • Issues, how to map: • association name • multiplicity • navigation direction • aggregation & composition • inheritance Price + getPrice () : int has 0..1 class Item { private name : String private price : Price public getPrice () … } Item(n,p) { name = n price = p } class Price { public getPrice () … } p = new Price() a = new Item(“Ale”,p) p : Price a : Item name = “Ale” price =
Converting UML classes to Java • Item • name : String • + getPrice() : int • + add(d : Discount) • Discount • val: int • + getValue() : int • + attach(x : Item) discounts has * [0..1] ordered, nonunique a = new Item(“Ale”) a.add(D) a.add(D) class Item { private name : String private discounts : List<Discount> public Item(…) … public getPrice () … public add(d:Discount) … } a : Item name = “Ale” discounts = D : Discount : List Q: how do you map e.g. [0..10] multiplicity ?
Converting UML classes to Java • Item • name : String • + getPrice() : int • + add(d : Discount) • Discount • val: int • + getValue() : int • + attach(x : Item) discounts item has * [0..1] ordered, nonunique Java has no direct support for bidirectional navigation. class Item { private name : String private discounts : List<Discount> public Item(…) … public getPrice () … public add(d:Discount) … } class Discount { private val : int private item : Item public Discount(…) … public getValue() { return val } public attach(x:Item) … } attach(x) { item = x ; x.add(this) ; } Q: so, how to implement if we change the multiplicity of “item” from [0..1] to 1 ?
Mapping aggregation & composition • Make sure you maintain asymmetry • For composition, make sure you don’t leak containment A B A A B a2 : A a1 : A X b : B
Mapping inheritance • Java has single inheritance • Multiple inh. has been discussed • But inheritance is “static” in Java (if you make a parent, you can’t turn it to a coordinator at the run time, vice versa) will be discussed more in Design Pattern Parent name addChild(c) Coordinator reportMiss()
Converting use-case / sequence diagram • Mapping use case mapping seq. diagram • How to map interactions sequence • “Interaction” a send a message m to b • Synchronous : sender waits for the receiver’s answer. • Else asynchronous • Synchronous send method call • Async more complicated charge(p) ok return arrow can also be implicit charge(p)
Mapping “sequencing” (of interactions) class System { buy() { basket = … customer = … if(basket.items.isEmpty()) throw … totprice= basket.getTotalPrice() assert totprice > 0 customer.charge(totprice) basket.reset() assert basket.items.isEmpty() } } : System c : Customer b : Basket : User opt [ b.items notEmpty()] getTotalPrice() buy() totprice { totprice > 0 } charge(totprice) reset() { b.items isEmpty() } Notice the sync. sends.
It is “design” … expect to fill details. : System i : Item b : Basket class Basket { items : List<Item> … getTotalPrice() { int s = 0 for (Item i : items) s += i.getPrice() return s } } getTotalPrice() getPrice() totprice
use unique nr. to identify matching reply/send. • you need to implement a matching mechanism Asynchronous send class Customer { String email boolean registered Customer(email) { this.email = email ; … unique = …. mail(email, unique) } static mailReply(unique) { c = … find matching cust. c.activate() } activate() { registered = true ; sys.add(this) } } : User : System register(email) <<create>> Cust(email) c : Customer mail(email) { registered } add(c) Sometimes, it is not realistic to impose on synchronous msg exchanges; e.g. the response time is long, e.g. via email. Then you will have to implement differently...
Persistence • Your business data is very important. • Persistence saving your business data • because your system can crash • because the data is too big to fit in memory • You want to rely on dedicated persistence technology database • reliable • performance • support for query, rollback, concurrency
Typical architecture Presentation (User Interface) Business logic buys Customer Item * save, load, query Persistence layer provides an abstract interface to save, load, and query objects to/from the database, that is independent from the specific database technology being used. persistence layer / data access management database Persistence
Relational db • Most popular, well proven technology • In mathematics, a relation R : A×B×C is a set of “tuples” from A,B,C, e.g. : { (a1,b1,c1), (a2,b2,c2) } • A “table” is a relation:
Some db terms Product Customer • attribute • row, column • key, primary key • foreign key • query • joint Transaction
Mapping class to table • You may need to add “shadow” attributes to support persistence • Object ID • Creation time • Update counter Customer Customer Name Email OID creationTime UpdateCtr
Mapping 1-to-many association Customer Name Email City Code Name 1 lives in * Customer City Via a foreign key on the “many”-side
Mapping many-to-many association Customer Name Email Item Name Price buys * * Transaction Date Customer Item Transaction With an association table..
Mapping inheritance Item Name Price • map the entire inheritance hierarchy to a single table, or : • map each class to its own table PC OpSys Item PC
Saving and loading objects • When you “load” a customer x, do you also expect that all objects navigable from x to be loaded as well? • Similarly, when you save x, do you need to also save all objects navigable from x? • From OO perspective: yes. • Additional implementation work “Bob” bob@bikini.com “Patrick” pat@bikini.com “Octo” boss@octo.net
Impedance mismatch • Between your OO application and its relational db back-end. • Objects’ “graph” structure do not map directly to tables. • Issues: • how to save/load/query such a structure to/from tables? • what to do with concurrent access ? (you can potentially pull a large graph of objects) • Available solutions: • Semi-automating it with a mapping framework • Use an object-relational DB instead • Use an OO DB
Some guide lines.. • Maintenance can be quite expensive! Important contributing aspects: • Complexity hard to understand, buggy, cost to fix bugs, testing cost • Flexibility if bad, then changing or adding features can be a real pain • Strategically towards those, important “variables” to balance: • Tactically: design patterns, refactoring, coding style,… • Encapsulation • Coupling • Cohesiveness • Inheritance
“Encapsulation” • Meaning …. • Hiding some part of your data/functionalities • packing related functionalities into one unit, and exposing only the needed one for public use. • Software built from encapsulated units is less complex. • OO gives you powerful mechanism for encapsulation
Balancing… • A cohesive class is easier to understand • Low coupling between classes contribute to less overall complexity • But often you have to balance them… delegation… • Product • name : String • price : int // e.g. in euro • + getPrice(c : Currency) : Int • Currency • code : String • + covert(c : Currency) 1 will have to do the currency conversion himself, which is not really a job for a Product.
Balancing… • Inheritance let you reuse code (less maintenance), but you get implicit coupling with superclasses. • Beware of deep inheritance trees Programmer may overlook influence of a superclass that is far up in the tree. • Duration • start • end • + isValid() • Discount • val • + getValue () MemberDiscount Registered Customer
Balancing… • When coding it is convenient to be able to access an object’s operations at will, but this introduces coupling. • Demeter “Law” (Holland 87): an object should only talk with its neighbors. • More structural: you open up many attributes/operations as package-private. But then all classes in the package are coupled together! You may pay the price when you want to modify some of them. Customer getPrice() Item getPrice() * Basket * Customer getPrice() Basket getPrice() Item getPrice() Meet Demeter, but in a way we trade off with Basket’s cohesiveness
Software metric • Quantitative indicator of a certain aspect of your program, e.g. its complexity. • Can be calculated with a tool • Help you to decide whether or not to refactor • Useful as a strategic instrument • Examples: • Line numbers • Counting coupling, inheritance depth etc • Halstead • Mc Cabe
Just for info Halstead Halstead approximates complexity in terms of effort to “read” the program: x = x + x ; x++ x = x + y ; z++ (alleen ter info)
Just for info Mc Cabe Mc Cabe approximates complexity in the numbers of “linearly independent” execution paths through the program. int P() { if (...) return 100 else return 0 } 0 4 1 3 0 2 1 5 2 ControlFlowGraph (CFG)
Just for info Metric for encapsulation etc for OO • Chen & Lu, 1993; simple, to “count”: • Encapsulation • Coupling • Cohesiveness • Inheritance • CL approximateencapsulation”of a class C by the sumof signature complexity of its public method. • more parameters more complex • complex typed parameter increasescomplexity
Inheritance and cohesion • CL approximate complexity due inheritance on a class C by the sum of: • # C’s methods (own + inh) • C’s inheritance distance • # C’s direct superclasses • # C’s subclasses • CL approx. cohesion by counting the number of groups of “related” methods in C. • Put method with “similar” param-types in the same group:add(discount), setName(name), remove(discount)
Tool support 32
Issues (in persistence) • Mapping: how to map your objects to the back-end DB • When you anticipate multiple users: • Performance • Optimizing your logical & physical data model • Concurrency • Security • We’ll discuss some of these • Related courses: db, distributed programming, cryptography
Some db terms Product Customer • attribute • row, column • key, primary key • foreign key • query • joint Transaction
Map to normalized tables… • What if we store our data like this? • Several “normal forms” to eliminate data redundancy • sometimes “de-normalize” to make certain queries faster • we only need 1x table • data redundancy wasting space + consistency problem • have to deal with “anomalies”, e.g. what to do if we want to delete Patrick ? • certain queries may be faster
Look at attributes dependencies • Let A,B,C be attributes in a table T • A,B C = C “depends on” A,B = if the values of AB uniquely determines the value of C • Let K = {A,B} be a “candidate” key of T ; C partially depends K if it only depends on part of K redundancy. not 2NF TrNr Prod is a candidate key here
So-called 2nd Normal Form • Table T is 2NF if it contains no partial dependency wrt any candidate key. • Transform the previous scheme: • Make sure you don’t lose information!
3rd Normal Form • T is 3NF if it is 2NF, and every attribute A which is not part of a candidate key, must depend only on a candidate key. not 3NF 3NF
Denormalization • But what if you frequently query the customers names and emails of given transactions? you will need to join often • To favor query speed : denormalize. not 3NF 3NF
You may have seen this: entity Relationship (ER) model … Product ID {PK} Name Price Customer ID {PK} Name Email purchase date nr * * Product Customer Purchase
Typical architecture Presentation (User Interface) Business logic buys Customer Item * save, load, query Persistence layer provides an abstract interface to save, load, and query objects to/from the database, that is independent from the specific database technology being used. persistence layer / data access management database Persistence
Concurrency clients A • Each functionality invoked by a client may require data from certain tables, and update to some rows. • Danger: collision. you need to lock your data! • Pessimistic locking safe, but does not perform • Optimistic locking • Blow up the complexity of your persistence layer • Error prone db B App C