Lösungsvorschlag Software Architecture FS08

Aus VISki
Wechseln zu: Navigation, Suche

Modularity, ADT, Designy by Contract and Concurrency (8 points)

Modularity, reusablilty, ADT and design patterns.

b

d

f: true, since the visitor needs to know implementation details of the objects it visits

Design by Contract

b: true because class invariants are 'and'-ed, hence stronger assertions can be introduced

c

Design by Contract (12 points)

class 
  BANK_ACCOUNT

feature
withdraw(v: INTEGER) is
  require TRUE
do
end

feature
balance: INTEGER

end

class STUDENT_ACCOUNT inherit
BANK_ACCOUNT redefine withdraw end

feature
withdraw(v: INTEGER) is
require else
balance >= v
do
  balance := balance - v
ensure
  balance_altered: balance = old balance - v
end

end

class B_A_NORMAL inherit 
BANK_ACCOUNT redefine withdraw end

feature
withdraw(v: INTEGER) is
require else
balance > v + fee
do
  balance := balance -v
ensure
  balance_altered: balance = old balance - v
end

feature
  fee: INTEGER

end

class B_A_BUSINESS inherit
BANK_ACCOUNT redefine withdraw end

feature
withdraw(v: INTEGER) is
require else
balance + credit > v
do
  balance := balance -v
ensure
  balance_altered: balance = old balance - v
end

feature
  credit: INTEGER
end

Abstract Data Types (16 points)

Writing and ADT for CREDIT_CARD (7 points)

TYPES

CREDIT_CARD

FUNCTIONS

Creators:

new_card: INTEGER x INTEGER --|--> CREDIT_CARD

Queries:

limit: CREDIT_CARD ----> INTEGER

balance: CREDIT_CARD ----> INTEGER

Commands:

settle: CREDIT_CARD ----> CREDIT_CARD

charge: CREDIT_CARD x INTEGER --|--> CREDIT_CARD

PRECONDITIONS

P1 new_card (limit: INTEGER) require limit > 0

P2 charge (c: CREDIT_CARD; amount: INTEGER) require amount + balance(c) <= limit(c) and amount > 0

AXIOMS

A1 limit(new_card(l: INTEGER)) = l

A2 balance(new_card(l: INTEGER)) = 0

A3 limit(settle(c: CREDIT_CARD)) = limit(c)

A4 balance(settle(c: CREDIT_CARD)) = 0

A5 limit(charge(c: CREDIT_CARD; a: INTEGER)) = limit(c: CREDIT_CARD)

A6 balance(charge(c: CREDIT_CARD; a: INTEGER)) = balance(c: CREDIT_CARD) + a

Proof of balance properties (6 points)

Prove that balance(c) >= 0:

Base case: using A2, new_card(l)

Induction assumption: is a correct expression of type CREDIT_CARD of length , i.e.

Induction step:

using A4

using A6, induction assumption for , and P2 for


Prove that

Base case:

new_card(l: INTEGER)

using A2

using A1

Hence: using P1 for the last inequality

Induction assumption:

is a correct expression of type CREDIT_CARD and length , that is:

and

Induction step (reuse inequalities found for balance above):

(see above) and using A3 and induction assumption, hence


using P2

using A5

since above we could show that a stronger statement was true


Proof of sufficient completeness (3 points)

We need to show that calling both query functions on any valid CREDIT_CARD expression will either return a value (different from a CREDIT_CARD), or a CREDIT_CARD expression which is one element shorter than the original one.


limit(new_card(l)) = l, using A1

balance(new_card(l)) = 0, using A2


Let be a valid expression of type CREDIT_CARD and length n, then:

limit(charge(c_n, a)) = limit(c_n) using A5

balance(charge(c_n,a)) = balance(c_n) + a using A6

limit(settle(c_n)) = limit(c_n) using A3

balance(settle(c_n)) = 0 using A4


Design Patterns I (26 points)

Identify patterns (12 points)

Bridge

CAR_FACTORY is the abstraction and CAR_FACTORY_IMP the implementation.

This is a structural pattern.

The bridge pattern observes separate abstraction and implementation inheritance trees. An abstraction has-a implementation object, and this client-supplier relation is referred to as the bridge. All methods in the deferred abstraction class are implemented in terms of the deferred implementation (the deferred classes being the topmost super classes in the corresponding hierarchies). Subtypes of the abstraction super class implement their methods in terms of the methods provided by said abstraction super class.

Abstract Factory

APPLICATION receives a factory object and CAR_FACTORY is the corresponding factory which makes the products desired by APPLICATION.

This is a creational pattern.

The deferred class CAR_FACTORY, or CAR_FACTORY_IMP provides an interface for the production of a complex product consisting of a number of other products (i.e. a car consists of wheels, the body, and an engine). Each of these subproducts (wheels, body, engine) come in different concrete implementation forms. The abstract factory pattern is used to implement specific versions of the interface provided by the deferred or abstract factory, where concrete versions of the abstract factory chose a specific concrete subproduct to be produced.

Builder

BMW_FACTORY_IMP has a concrete builder object and CAR_BUILDER is a generic class which implements the builder.

This is a creational pattern.

Just like the abstract factory pattern, the builder pattern is concerned with assembling complex products from a number of subproducts, and making specific decisions about the corresponding concrete (implemented) subproducts. Contrary to the abstract factory pattern, the builder pattern does not return the final complex product immediately. Instead, as a last step, the client of the builder (BMW_FACTORY_IMP in this case) will call the feature last_car on the corresponding builder in order to obtain the final product.


Build Mercedes cars (14 points)

Question.png

Dem Autor des Lösungsvorschlags stellt sich eine Unklarheit betreffend der Prüfungsfrage oder deren Lösung:
I am not sure whether implementing a new concrete CAR_FACTORY_IMP is sufficient.
Hilf mit, die Qualität dieser Seite zu verbessern, indem du eine eindeutige Lösung einfügst oder auf der Diskussionsseite dieses Themas deine Meinung äusserst.

class
	MERCEDES_FACTORY_IMP

inherit
	CAR_FACTORY_IMP
	
feature {NONE}
	
	make is
			-- blah
	do
		create sedan_builder
		create convertible_builder
		create station_builder
	end
	
feature
	
	build_sedan is
			-- 
		do
			sedan_builder.build
			last_card := sedan_builder.last_product
		end
		
	build_convertible is
			-- 
		do
			convertible_builder.build
			last_card := convertible_builder.last_product
		end
		
	build_station is
			-- 
		do
			station_builder.build
			last_card := station_builder.last_product
		end
		
feature
	
	sedan_builder: CAR_BUILDER[MERCEDES_SEDAN_BODY, MERCEDES_ENGINE, MERCEDES_WHEEL]
	convertible_builder: CAR_BUILDER[MERCEDES_CONVERTIBLE_BODY, MERCEDES_ENGINE, MERCEDES_WHEEL]
	station_builder: CAR_BUILDER[MERCEDES_STATION_BODY, MERCEDES_ENGINE, MERCEDES_WHEEL]
	
end

Web shop (16 points)

Copy & Paste

The copy and paste approach is not a good solution.

First, SALES_ORDER_GERMANY is not a meaningful descendant of SALES_ORDER. One should abstract SALES_ORDER into a general class describing sales and order, and then inherit from this new abstraction in order to implement SALES_ORDER_... for Switzerland and Germany.

Question.png

Dem Autor des Lösungsvorschlags stellt sich eine Unklarheit betreffend der Prüfungsfrage oder deren Lösung:
I was going to state that the proposed approach would violate the open-closed principle - but I am not certain about it. What slides in the lecture notes discuss this question?
Hilf mit, die Qualität dieser Seite zu verbessern, indem du eine eindeutige Lösung einfügst oder auf der Diskussionsseite dieses Themas deine Meinung äusserst.

Case distinction

This approach is more meaningful than the copy & paste approach.

However, using this approach one ends up with a lot of case distinctions if the specification changes and more country-specific processes need to be carried out. Also, using object-oriented programming one is able circumvent this sort of case distinction. That is, using inheritance and polymorphism would be a better approach which would make use of the concepts that modern OO programming provides to us.

Good about this approach is that, assuming taxing is the only country-specific difference, it is quite short and requires little code.

A solution based on inheritance

Question.png

Dem Autor des Lösungsvorschlags stellt sich eine Unklarheit betreffend der Prüfungsfrage oder deren Lösung:
I don't know how to answer this one
Hilf mit, die Qualität dieser Seite zu verbessern, indem du eine eindeutige Lösung einfügst oder auf der Diskussionsseite dieses Themas deine Meinung äusserst.

This approach which utilizes inheritance and polymorphism is the modern approach implied by OO technologies.

Problems may arise if one assigns dynamically an erroneous object reference, and begins to carry out country-specific operations not applicable to the actual country?

A design pattern might help

I would utilize the abstract factory pattern.

There should be deferred classes FORM, TAXES, PROCESS_ORDER, and RECEIPT. All of these classes define interfaces with the obvious meanings: FORM defines the interface of the web shop form to be filled out etc.

One can then implement country-specific concrete classes of these deferred classes, i.e. FORM_CH, FORM_DE, TAXES_CH, TAXES_DE, etc.

A deferred class ORDER_FACTORY defines the interface of the notion of receiving an order via the web form, processing it, taxing it, etc., and shipping it to the customer.

One can now implement concrete factories ORDER_FACTORY_CH, and ORDER_FACTORY_DE which implement the corresponding interface, using the country specific products of type FORM, TAXES, etc.

The actual shops in Switzerland and Germany will now receive an instance of the corresponding concrete factory, and can use the corresponding public interfaces to receive, process, and ship orders.

Visitor & Composite Pattern (16 points)

Theoretical Questions (6 points ??)

Pattern Categories (2 points)

Composite pattern: Structural pattern

Visitor pattern: Behavioural pattern

Visitor and open-closed principle (2 points)

In the visitor pattern you always have a deferred visitor class which provides the necessary interface, and a number of concrete implementations of said interface which implement the deferred methods in a specific way.

This pattern adheres to the visitor pattern since it consists of an abstract interface which is closed to modifications (except for error correction), and one inherits from this abstract interface in order to change the behavior. One does not change the interface.

Thus the deferred visitor (or abstract interface) is closed to modification but can be inherited from and changed (i.e. it's open too).

Class Diagrams (2 points)

Lecture notes 2009

Pattern Implementation (10 points)

Accept (3 points)

class
	COMPOSITE_FILE
inherit COMPONENT

...

feature
	accept(a_visitor: VISITOR) is
			-- blah
		do
			a_visitor.visit_file(Current)
			
		end
class
	COMPOSITE_FOLDER
inherit COMPONENT

...

feature
	accept(a_visitor: VISITOR) is
			-- blah
		do
			a_visitor.visit_folder(Current)
			
		end

Visit (7 points)

class
	VISITOR_CHECK_CHANGE
inherit 
	VISITOR

...

feature
	visit_folder (a_folder: COMPOSITE_FOLDER) is
			-- blah
		do
			from
				a_folder.children.start
			until
				a_folder.children.after
			loop
				a_folder.children.item.accept(Current)
				a_folder.children.forth
			end
		end
		
	visit_file (a_file: COMPOSITE_FILE) is
			-- blah
		do
			if a_file.has_changed then
				io.put_string(a_file.name)
				io.new_line
			end
		end