אביב תשס"ה JCTתיכון תוכנה: ד"ר ראובן גלנט1 פרק 8 נקודות...

Post on 20-Dec-2015

228 views 9 download

Transcript of אביב תשס"ה JCTתיכון תוכנה: ד"ר ראובן גלנט1 פרק 8 נקודות...

1תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

8פרק 7-9נקודות חשובות בתרגילים

2תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

1. Initializer

3תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Inheritance• Make the PressureSensor and TemperatureSensor

inherit from the base class Sensor.• Add directed associations from the Motor to the

PressureSensor and to the TemperatureSensor.• Set the multiplicity to 1.

4תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Base Class Sensor• Add attribute name of type OMString• Add a constructor that receives an argument

aName of type OMString • Initialize the attribute in the initializer name(aName)• Create an operation print with implementation

std::cout << name << “ “;

5תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Base Class Sensor-Sensor.cpp

//file Sensor.cpp#include “Sensor.h”

Sensor::Sensor(OMString aName): name(aName) { }

void Sensor::print() {std::cout << name << “ “;}

6תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Motor Class• Create a constructor that creates instances of

both types of Sensor:• setItsTemperatureSensor(new TemperatureSensor(“T1”));• setItsPressureSensor(new PressureSensor(“P1”));

7תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Class Motor- Motor.cpp

//file Motor.cpp#include “Motor.cpp#include “Sensor.h” Motor::Motor() { setItsTemperatureSensor(new TemperatureSensor(“T1”)); setItsPressureSensor(new PressureSensor(“P1”));}

8תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Derived Sensor Classes• For both derived Sensor classes:• Create a constructor that has an argument

aName of type OMString• Set the Initializer to Sensor(aName)

Sensor(aName) invokes the Sensor constructor so as to initialize the name field of the base class.

9תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Derived Classes: TemperatureSensor.cpp

//file TemperatureSensor.cpp

#include “TemperatureSensor.h”

TemperatureSensor::TemperatureSensor(OMString aName): Sensor(aName) { }

10תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Animating• Create a Test component and a Debug configuration

that creates an initial instance of the Motor class• Save / Generate / Make / Run • With the browser, note that there are two instances of

Sensor. Each Sensor has a name that has been initialized.

11תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

User Types• Using the browser, right-click on the Default

package and select “Add New Type” • add a type tTempUnits declared as

– enum tTempUnits { CELSIUS, FAHRENHEIT };

An alternative declaration is :enum %s { CELSIUS, FAHRENHEIT }.

12תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Attribute Unit• Add an attribute unit of type tTempUnits for the

TemperatureSensor.• Add an argument to the TemperatureSensor

constructor called aUnit of the same type • In the initializer add ,unit(aUnit)

13תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

TemperatureSensor• Change the read operation to :

std::cout << “Temperature = “ << rand() % 100 << “deg “;

if ( unit == CELSIUS )

std::cout << “C” << std::endl;

else

std::cout << “F” << std::endl;

• In the Motor constructor, add the argument “CELSIUS” as follows:

setItsTemperatureSensor (new TemperatureSensor( “T1”, CELSIUS));

14תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

2. Container Classes (OMCollection)

andIterators

(OMIterator)

15תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Using OMIterator• Rhapsody provides an OMIterator class that

can be used as follows to iterate through a container:

OMCollection<Sensor*> itsSensor; // a container

OMIterator<Sensor*> iSensor(itsSensor);iSensor.reset(); // point to firstwhile ( *iSensor != NULL ) { (*iSensor)->print(); // print ++iSensor; // point to next}

16תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Collection of Sensors• Load the “Virtual” project and save as “Collection”• Delete from Model the relations between the Motor and

the Sensors. Check in the Browser that these relations have been deleted from the model not just the view.

• Add a directed aggregation itsSensor from the Motor to the Sensor. Set Multiplicity to * (many).

17תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

OMCollection• Delete implementation of Motor constructor• Save / Generate / Examine code for Motor• Note that the relation has been implemented as a collection of

Sensors:

OMCollection<Sensor*> itsSensor;• Note also that there is an operation

addItsSensor(Sensor* p_Sensor);

18תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

OMCollection: Motor.h#ifndef Motor_H #define Motor_H #include "PressureSensor.h"#include "TemperatureSensor.h"class Sensor;public : //defined by user void addSensor(); void deleteSensor(); void pollSensors();

public: //defined by Rhapsody OMIterator<Sensor*> getItsSensor() const; void addItsSensor(Sensor* p_Sensor); void removeItsSensor(Sensor* p_Sensor); void clearItsSensor();

protected : OMCollection<Sensor*> itsSensor;};#endif

19תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Adding to OMCollection• In the motor constructor add Sensors:

– addItsSensor(new TemperatureSensor(“Sensor1”,CELSIUS));

– addItsSensor(new TemperatureSensor(“Sensor2”,FAHRENHEIT));

– addItsSensor(new PressureSensor(“Sensor3”) );

20תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

2.a Dependencies

21תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Dependencies• In order to compile, the Motor needs to include

the Pressure and Temperature Sensors header files. To do this we will add dependencies from the Motor to those classes:

• Double-click on each dependency and select the stereotype Usage.

22תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Implementation Includes• Alternatively instead of drawing dependencies,

we can just modify the properties for the Motor class and for CPP_CG->Class->ImpIncludes add TemperatureSensor.h,PressureSensor.h

CPP_CG means C++ Code Generation.

23תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Multiple Relation• Save / Generate / Make / Run• Show that the Motor has a collection of three

Sensors.

24תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Statechart• Create a simple Statechart for the Motor class

that calls a pollSensors() routine every two seconds.

25תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

pollSensors()• Create the pollSensors() operation that will

poll all the Sensors in the collection:

Note that if any more Sensors of any other type are added, the operation still functions!

OMIterator<Sensor*> iSensor(itsSensor);for ( iSensor.reset(); *iSensor; ++iSensor ) { (*iSensor)->print(); (*iSensor)->read();} cout << "---------------------" << endl;

26תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Extended Exercise• For the Sensor class, add a static attribute

numberOfSensors of type int with initial value 0.

• In the Sensor Constructor add numberOfSensors++;

• For the Sensor class, add a virtual Destructor with implementation : numberOfSensors--;

• Add the following to pollSensors() cout << “Number of sensors = “ << Sensor::getNumberOfSensors() << endl;

• Generate code and execute to check that numberOfSensors = 3.

27תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

3. Threads, Active Classes, Statechart Inheritance

28תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Concurrency• We want each Sensor to run on its own thread

(active class). • To do so, we need each Sensor to be

Reactive (class that waits for events). • So we will create a Statechart for the base

Sensor class as follows:

29תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Active Classes• With the browser, change the concurrency of

the Sensor class from sequential to active.

30תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Inheriting Behavior• Open the Statecharts for the PressureSensor

and TemperatureSensor. Note that they have inherited the base class Statechart.

• Specialize the behavior of the TemperatureSensor as below:

Grayed out indicatinginherited behavior

31תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Starting the Behavior• Add a call to startBehavior() from the

TemperatureSensor and PressureSensor constructors to initialize the statecharts.

If we had used a composite class, Rhapsody would have done this for us, but that would have been too easy !

32תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Multi-threads• Save / Generate / Make / Run• Check that there are four active threads.• Setting the focus to a particular thread displays

the call stack and event queue for that thread.

There will always be one thread called mainThread.

33תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Suspending Threads• Note that a thread can be suspended.

34תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Problems with the Design• With the current design there are a few

potential problems:– The Motor class needs to know about all

the different types of Sensor.– If another class wants access to the

Sensors, it too will need to depend upon all the different types of Sensor.

– Starting the behavior of a Sensor, in the constructor is not very elegant.

– Adding a new type of Sensor means finding and modifying all classes that use Sensor.

35תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

4. Singleton, Abstract Factory

36תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

Improving the Design• Using the “factory method design pattern” will

solve all these concerns.• A SensorFactory class can be introduced that is

used by all classes ( ex: Motor ) that need to get a Sensor. This decouples the Motor class from the actual Sensors and can also start the behavior of the Sensors.

• The SensorFactory will be implemented using the “Singleton design pattern” (to ensure that there is only one instance of SensorFactory).

See the “SensorFactory” example.

37תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

The Improved Design

38תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

The Singleton Design Pattern I

Protectedconstructor

Static attribute

39תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

The Singleton Design Pattern II

Static factoryoperation

Calling thecreateRandomSensor

operation

40תיכון תוכנה: ד"ר ראובן גלנטJCT אביב תשס"ה

SensorFactory::createRandomSensor()Sensor * SensorFactory::createRandomSensor(){ Sensor* aSensor; OMString aName; char index[10];

//itoa(Sensor::getCount(), index, 10); strcpy ( index, "1" ); aName = "Sensor" + OMString(index);

switch ( rand() % 4 ) { default: case 0: aSensor = new TemperatureSensor( aName, CELSIUS ); break; case 1: aSensor= new TemperatureSensor( aName, FAHRENHEIT ); break; case 2: aSensor = new PressureSensor( aName ); break; case 3: aSensor = new SpeedSensor( aName ); break; } aSensor->startBehavior(); return aSensor;}