370 likes | 617 Views
Classes. Ranga Rodrigo. Classes. Classes Versus Objects. Many Objects of a Class. Attributes. Methods. Features. Counter Example. Counters store (and make available through a display) a number.
E N D
Classes Ranga Rodrigo
Counter Example • Counters store (and make available through a display) a number. • Every time the user clicks a button, or similar interface widget, the number stored is increased. • There is a reset button, to set the count back to 0. • There will usually be a maximum permissible count value.
Attributes in Our Counter • The role of a counter is to store a numeric value. • We can define an attribute which stores the current value of the counter.
COUNTER Class in Counter.e File class COUNTER feature value : INTEGER end
value Attribute • This attribute is visible to all classes that use the counter class (client code). • In Java or C++ it is normal to make attributes private • to prevent client code changing the value of the attribute , and • to protect client code from modification if the representation of the attribute changes. • In Eiffel, these benefits are supported in different ways • Client classes have read-only access to attributes. • Uniform access.
class • MAIN • create • make • feature • c : COUNTER • make is • do • create c • io.put_integer(c.value) --Read access ok • c.value := 42 --Compilation error here • end • end
Uniform Access • If the type of an attribute is changed, the original attribute can be replaced by a function. • Eiffel's syntax ensures that client code will not be affectedby such a change. • This is known as the Uniform Access Principle. • There is no way for client code to tell whether an “attribute” of a class is implemented as an attribute or as a function.
class • COUNTER • feature • value_rep : REAL • value : INTEGER is • do • Result := value_rep.floor • end • end
Class Invariants • The collection of attributes in a class is sometimes said to define the state of instances of the class. • A class invariant is a property which specifies which are the legitimate values of a class's attributes.
class COUNTER feature value : INTEGER invariant value_in_range: 0 <= value and then value < 1000 end
Class Invariants • An invariant section can be written at the end of a class text, and can contain any number of Boolean conditions. • Each condition can be given a label to help identify it. • There are two main benefits: • Documentation. • Debugging: an Eiffel project can be configured to check invariants at run-time.
Constructors • Constructors, or creation routines as they are called in Eiffel, initialize attribute values when a new object is created.
class COUNTER creation make feature value : INTEGER maximum : INTEGER make( max : INTEGER ) is do maximum := max end invariant value_in_range: 0 <= value and value <= maximum end
Calling the Constructor • Because make is defined here to be a creation routine, whenever an instance of the counter class is created, the desired constructor must be called: • create c.make(9999)
make( max : INTEGER ) is require valid_maximum: max > 0 do maximum := max ensure value_initialized: value = 0 max_initialized: maximum = max end
Old • Sometimes, a postcondition should compare the value before the routine ran with its value after. The original value can be accessed using the keyword old. increment is require not_at_maximum: value < maximum do value := value + 1 ensure value_incremented: value = old value + 1 maximum_constant: maximum = old maximum end
Precondition • The precondition states that the routine can only be successfully called if the maximum value has not been reached. • Notice that the body of the routine does not check that the value is less than the maximum. • As we will see later, this is part of the design by contract (DBC) philosophy.
Precondition • We should now add to the class a function which allows clients to check whether or not the counter is at the maximum value. • Without this, they have no way of checking that the precondition is true before calling increment. • A function is a routine that returns a value. Each function has a predefined local variable called Result: the value in this variable when control returns to the caller is the return value of the function. • The return value can be specified by using Result in the function's postcondition.
at_max : BOOLEAN is do if value < maximum then Result := false else Result := true end ensure Result = (value = maximum) end
Incrementing • It would be better to use this function to define the precondition of increment: this means that the details of the check are written in one place only, and hence that the code is more maintainable. increment is require not_at_maximum: not at_max do ... end
Design by Contract (DBC) • One important aspect of design by contract is the specification of classes using • invariants, • preconditions and • post-conditions.
EiffelStudio Support for DBC • EiffelStudio allows controls over which aspects of a class's specification are checked at runtime. • Typically, you might check everything when developing a program, and only preconditions when it was delivered to a client. • Contract view shows the specification but omits the implementation of routines. • This gives enough information for a client to use the class.
DBC in Java • Java does not support DBC in the integrated way that Eiffel does. • Assertionfacility which can be used to provide some of the same functionality. • Program must be run with enableassertionsor esflag. • java -ea Main • Then an exception will be raised and the execution terminated if any assertion is false
public class Counter { private int value ; private int maximum ; public Counter(int max) { assert max > 0 : "Precondition failure: Counter.Counter" ; value = 0 ; maximum = max ; call_invariant() ; assert value == 0 && maximum == max : "Postcondition failure: Counter.Counter" ; } CONTD.
CONTD. public intgetValue() { return value ; } public void call_invariant() { assert 0 <= value && value <= maximum : "Counter invariant failure" ; } }
Eiffel and Java DBC: Differences • Eiffel syntax clearly separates the contract of the class from its implementation. • Java provides no way of calling the class invariant automatically at the appropriate times. • Java does not provide an easy way of accessing the old values of attributes.