700 likes | 743 Views
Learn about the definition and anatomy of application frameworks, fulfilling the framework contract, building frameworks, and examples of application frameworks. Understand the Model-View-Controller (MVC) framework design pattern and its elements: Model, View, and Controller. Dive into interaction scenarios, instantiation scenarios, and the framework reuse lifecycle. Discover key concerns in developing reusable assets and the importance of isolating and encapsulating variabilities within an application domain.
E N D
Chapter 13 Application Framework
Outline • Definition & anatomy • Fulfilling the framework contract • Building frameworks • Examples
Outline • Definition & anatomy • Fulfilling the framework contract • Building frameworks • Examples
Definition • An application framework may be roughly defined as a set of interacting object that, together, realize a set of functions.
An application framework may be described by the equation: Application Framework=a blueprint + component realization
The anatomy of a framework • A set of participant of the framework • A set of relationships between the participants of the framework • A set of interaction scenarios between the participants of the framework
Update Display View Controller Notification State data Application calls Model MVC framework
Model: The model is the part responsible for the application’s state and behavior, and for notifying the other components of state changes. • A simply define as follows: interface Model { void iChanged (String aspect, Object value); Object getState (); }
View: The view is the part responsible for the graphical display. • A simply define as follows: interface View { void update (String property, Object from, Object value); void display (); }
Controller: The controller is the component that is responsible for reacting to user inputs, and for translating them into actions to be execute on the application side. • A simply define as follows: interface Controller { void KeyPressed (String key, Point cursorPt); void leftMouseButtonPressed (Point cursorPt); void rightMouseButtonPressed (Point cursorPt); }
What we get in this simplistic MVC framework? • The mere description of the interface of the participant is far too little information to understand how the framework works. • We don’t know half the story without seeing the interaction between the various methods.
1 Our presentation of the interfaces was accom-panied by textural descriptions, which expli-cated(解釋) both the relationships and the interactions
2 There are two basic interaction paths through the various components: c.leftMouseButtonPressed () →m.<apply function> m.<change state> →m.ichanged (stateVar, val) → v.update (stateVar, m, val) The description of the scenarios is referred to as message sequence, and is one way of representing the interaction behavior or interobject behaviorthat is inherent in the framework.
leftMouseButtonPressed (…) update (…) display () getState () iChanged(…) Contr-oller View Model Figure 13.2 The participants represent pluggable components into an interaction infrastructure
Interaction infrastructure The smalltalk MVC framework includes classes for handling low-level interface events that connect the event management functionalities of the host windowing system with controllers. We refer to that part of the framework as the interaction infrastructure
Framework will typically come with simple realizations of some of the participants. Controller View Model Customer code
Instantiation scenario • Framework users need to know: how to assemble the various components
Example: | myModel myView myController | “instantiate CheckingAccount” Account := CheckingAccount new “create view for account” myView :=MyViewClass new: account. “set the controller to a MyControllerClass” myView controller: (MyControllerClass new).
Describe a framework for the user, we need to specify the following: • The set of participants of the framework, in term of the interfaces that they have to support • The set ofrelationships between them • The set of interaction scenarios between the participants that are mediated by the interaction infrastructure of the framework • The set of instantiation scenarios, showing how to assemble an instance of the framework
The framework reuse lifecycle • Specify the need in terms that can be match against the available descriptions of the reusable artefacts. • Search and retrieve the most relevant artefacts • Assess(評估) their reuse potential. • Select the best fit candidate, and adapt it to the current need. • Integrate it in the current application.
Outline • Definition & anatomy • Fulfilling the framework contract • Building frameworks • Examples
Key concern in developing reusable assets(資源) • Key concern in developing reusable assets is to identify, isolate, and encapsulate the variabilities within an application domain in such a way to maximum the common pars, and to constrain the development of the variable part. • For the case of object frameworks, given a set of objects that we know we need, and that have to collaborate to achieve a set of functions.
The concern • If we break the necessary collaboration between components, we can make it possible to: • Implement as much of the common parts as possible • Interchange the collaborating components with little or no effect on the rest of the components.
Design Pattern • Design pattern are use to mediate the interactions within an object framework. This is an indication of both, where to find good design pattern, and how to build good object frameworks:
Design Pattern (cont.) • Good application frameworks are a source for good design patterns. • Once we have identified the components of a framework, and their semantic dependen-cies, we can minimize the implementation of those dependencies by applying design patterns.
Figure 13.4 Frameworks accommodate variab-ilities by instantiating appropriate design patterns
Component substitutability • When we select classes to play the roles of specific participants, we use inheritance, polymorphism, and dynamic binding, to make sure that an instance of the framework will work properly
Inheritance • The actual participants are subclasses of abstract that represent the participants. • Type Conformance. Ensuring the type conformance of the actual participants to what is expected of them in the framework. • Extension. The abstract classes are not only used to represent obligations but also provide some of the behavior.
Polymorphism • We allow the code of the framework that was written generically for the participants’ classes to work with actual implementations of those participants.
Dynamic binding • We enable polymorphic code to always invoke the method implementations that are most appropriate to the actual object being used.
Example Class OTC_Dispatcher: . . .{ //participant: provide parts of the implementation Collection<OTC_Job>* jobQueue; Public: OTC_Dispatcher (Collection<OTC_Job>* jobs = null ) { setJobQueue (jobs); …} (1) virtual void log (OTC_Job* job) { cout << “Executing: “<< job <<endl; } (2) void setJobQueue (Queue<OTC_Job>* queue) {…} (3) int dispatch () { //general and shouldn’t be redefined int nbJobs = 0 ; (3.1) while (jobQueue -> hasMoreElement () ) { (3.2) OTC_Job* nextJob = selectFirstJob () ; //inheritance, (3.3) nextJob ->start (); //polymorphism, //and dynamic binding
(3.4) log (nextJob); nbJobs ++; } return nbJobs; } … (4) virtual OTC_Job* selectFirstJob () = 0; //all subclass of OTC_Dispatcher have //to provide their own definition … } Class OTC_Job: … { //participant: provide parts of the implementation Public: (5) virtual void start () { initialise (); run (); end (); } (6) virtualvoid initialise () = 0; (7) void run () {…} (8) virtualvoid end () = 0; }
The same ex. in java interface Dispatcher { //separate the interface and implementations. publicvoid log (Job aJob); public void setJobQueue (Collection Queue); public int dispatch (); public Job selectFirstJob (); } interface Job { public void start (); public void initialise (); public void run (); public void end (); } Assume that we have two classes OTC_Dispatcher and OTC_Job which implement this two interface respectively.
Departures from the C++ implementation • Participants classes do not have to inherit from any particular class • The provided abstract classes (OTC_Dispa-tcher and OTC_Job ) refer to each other through the Dispatcher and Job interfaces, and not by name, which would allow them to work not only with each other but also with any other class that implements the corresponding interface.
Another issue: Assembling participants to instantiate a framework • Despite our best efforts to abstract the roles of the components, we could still be left with implementation-level dependencies between the participant components, which are not adequately expressed by abstract interface.
Example • In a portable GUI framework that can emulate various native interfaces, there is the implicit assumption that the realization of the CompositeContainer widget be compatible with the TextView widget.
Button Panel XButton XPanel WButton WPannel Figure 13.5 Mutually consistent specializations
An acceptable solution: factory class • Factory class (ref. Design Pattern [Gamma et al. 1994]) consists of including, in the framework, a class whose only purpose is to manufacture(生產) objects that play specific roles.
In this case, an abstract factory class would look like: • abstractclass WidgetFactory { abstract public Button getButton (); abstract public Panel getPanel (); abstract public ListView getListView (); … }
Then we can have subclasses of the widget factory that would create mutually consistent instances of the various participants, as in: class Win32WidgetFactory extends WidgetFactory { public Button getButton () {return new WButton (); } public Panel getPanel () {return new WPanel (); } public ListView getListView () {return new WlistView (); }
and : class XWidgetFactory extends WidgetFactory { public Button getButton () {return new XButton (); } public Panel getPanel () {return new XPanel (); } public ListView getListView () {return new XlistView (); }
Composability requirement (ch. 12) • For reusable artifacts to be composable, a number of criteria have to met: • Two components are able to communicate and to interoperate. • They need to be independent
Composition issue • How to compose objects without creating dependencies between them? • An acceptable solution: Adapter pattern
Adapter pattern (1) • Problem • You want to use a class that calls a method through an interface, but you want to use it with a class that does not implement that interface. • Solution • Convert the interface of a class into another interface client expect. • Adapter lets classes work together that couldn’t otherwise because of incompatible interface.
Adapter pattern (2) • Structure • A class adapter uses multiple inheritance to adapt one interface to another.
Adapter pattern (3) • Structure • An object adapter relies on object composition
Adapter pattern (4) • Consequences • Class and object adapters have different trade-offs. A class adapter • a class adapter won’t work when we want to adapt a class and all its subclasses. • Let Adapter override some of Adaptee’s behavior, since adapter is a subclass of Adaptee. • Introduces only one object, and no additional pointer indirection is needed to get to the adaptee.
Adapter pattern (5) • An object adapter • Lets a single adapter work with many adaptees-the adaptee itself and all of its subclasses (if any). • Make it harder to override adaptee behavior. It will require subclassing adaptee and making adapter refer to the subclass rather than the adaptee itself.
Outline • Definition & anatomy • Fulfilling the framework contract • Building frameworks • Examples