+ All Categories
Home > Technology > (5) c sharp introduction_object_orientation_part_ii

(5) c sharp introduction_object_orientation_part_ii

Date post: 24-Jun-2015
Category:
Upload: nico-ludwig
View: 73 times
Download: 2 times
Share this document with a friend
Description:
- When to use Inheritance - Polymorphism - Abstraction - Abstract Types - Interfaces - Sealed Types - Static and dynamic Type of Objects
Popular Tags:
21
Nico Ludwig (@ersatzteilchen) (5) Introduction of C# – object-oriented Programming – Part II
Transcript
Page 1: (5) c sharp introduction_object_orientation_part_ii

Nico Ludwig (@ersatzteilchen)

(5) Introduction of C# – object-oriented Programming

– Part II

Page 2: (5) c sharp introduction_object_orientation_part_ii

2

TOC

● (5) Introduction of C# – object-oriented Programming – Part II

– When to use Inheritance

– Polymorphism

– Abstraction

– Abstract Types

– Interfaces

– Sealed Types

– Static and dynamic Type of Objects

Page 3: (5) c sharp introduction_object_orientation_part_ii

3

Everything is an Object

● In .Net all intrinsic and user defined types partake in the framework.

– This is possible, because each type drives from the class System.Object.

● The type System.Object can also be referred to with the alias C# keyword object.

– This is often called "cosmic hierarchy".

– Wherever an object of type object can be used, a user defined type can be used also.

● This is the substitution principle (e.g. Console.WriteLine() along with object.ToString()).

– So, each new user defined type is a .Net object.

● User defined types itself can act as base types to manage substitution.

– Imagine the recently presented class Car and a new class Garage.

– In Garages Cars are tried to be started with Car's method StartEngine().

– In Garages it should be allowed to start all sorts of Cars.

– Because the behavior of all Cars is the same, however, we can start the engine.

– All Cars have the publicized method StartEngine() in their public interface.

Page 4: (5) c sharp introduction_object_orientation_part_ii

4

Using Cars in Garages

● The class Garage and its implementation of the method TryToStartCar().

● We can pass any kind of Car to TryToStartCar(), e.g. Bus.

– Because Bus is inherited from Car.

– I.e. a Bus is a Car.

– (And Car has an Engine.)

public class Garage {/// <summary>/// Tries to start the passed Car./// </summary>/// <param name="car">The Car to start.</param>public void TryToStartCar(Car car) {

car.StartEngine();}

}

Garage

+ TryToStartCar(car : Car)

Car

Bus

Engine

Garage joesStation;Car seatLeon = new Car();Bus mercedesIntegro = new Bus();joesStation.TryToStartCar(seatLeon); // OK!joesStation.TryToStartCar(mercedesIntegro); // OK!

● OO seems to be perfectly good to build GUIs,because the visual representation of GUIs can bedirectly simulated with oo UDTs and oo paradigms(e.g. has and is associations of forms and controlsand also the application of design patterns). - Inopposite to procedural or functional programming.

Page 5: (5) c sharp introduction_object_orientation_part_ii

5

Intermezzo: Inheritance for white-box Reuse

● Aggregation: Using a Car's public interface is black-box reuse.

– All the critical stuff is encapsulated, declared private or protected.

● Inheritance: Using a Car's protected interface is white-box reuse.

– Subtyping is needed to access the protected stuff.

– Subtypes have to know how to work with protected members!

– Subtyping breaks encapsulation to certain degree!

– Never ever use inheritance for plain reuse, this is an antipattern!

● Inherited/derived types have access to public and protected members of the base type.

– protected members are only accessible within the "family".

● E.g. access and handling of the StarterSystem of Cars is too critical to be public!

● Car's subtypes must know how to use the StarterSystem (maybe the subtype Bus needs to handle the StarterSystem in a different way).

● In fact the protected members of our types shouldbe as good documented (e.g. via XML comments)as the public members to make white-box reusepossible!

Page 6: (5) c sharp introduction_object_orientation_part_ii

6

When to use Inheritance?

● Inheritance can be used to express:

– Generalization/specialization associations.

– The substitution principle and polymorphism.

– White-box reuse.

● By far the most important usage is substitution principle and polymorphism.

– Normally it comes along with generalization/specialization associations.

– The reuse of the interface (the behavior) is the primary usage aspect!

– White-box reuse is a secondary aspect!

● Inheritance for reusing interfaces is the basis for most design patterns.

Page 7: (5) c sharp introduction_object_orientation_part_ii

7

Polymorphism – chooses Implementation during Run Time

● A derived type inherits the public interface from its base type.

● Sometimes the inherited default implementation of a method is inadequate!

– E.g. Car's method StartEngine() inherited by new subtype "VintageCar" must possibly use a crank, not the Engine object directly!

● Therefor a derived type can override the inherited default implementation.

– In C# base type methods that are "override able" must be marked as virtual.

– E.g. from base type object the method ToString() must be overridden very often.

● Overriding (late binding) is not overloading (early binding)!

– Overriding takes effect during run time, overloading during compile time!

– Overrides in a subtype mustn't change the signature of the overridden method.

Page 8: (5) c sharp introduction_object_orientation_part_ii

8

The VintageCar Example

● VintageCar can override Car's (VintageCar's base-type) method StartEngine().

public class Car {/// <summary>/// Starts the Car, default implementation./// </summary>public virtual void StartEngine() {

_theEngine.Start();}

}

public class VintageCar : Car {/// <summary>/// Starts the Car, special implementation for Cars with crank./// </summary>public override void StartEngine() {

if (HasStarter) {// Then: call StartEngine() of the base class Car!base.StartEngine();

} else {while (CrankUntilStarted()) { /* pass */ }

}}

}

Car

+ HasStarter() : bool+ StartEngine()

VintageCar

- CrankUntilStarted() : bool+ StartEngine()

● The names of the parameters in an overridingmethod need no to be same as in the to-be-overridden method.

Page 9: (5) c sharp introduction_object_orientation_part_ii

9

Polymorphism everyday: Overriding ToString()

● In .Net all types do implicitly inherit from the type object.

● And every type inherits methods from object, the most important ones are:

– ToString()

– Equals()

– GetHashCode()

● We'll often have to override these methods in order to provide special behavior.

public class Bus : Car { // (members hidden)public override string ToString() {

return string.Format("A Bus with {0} vacant seats.",_presentSeatBenches.Length - _occupiedSeatBenches.Length);

}}

Car car = new Car();Console.WriteLine(car); // Calls ToString().// >Car

Car bus = new Bus();Console.WriteLine(bus); // Calls Bus' special ToString().// >A Bus with 10 vacant seats.

Page 10: (5) c sharp introduction_object_orientation_part_ii

10

Where is Polymorphism happening?

● Whose implementation of method StartEngine() is called in a Garage?

● This is decided during run time → polymorphically!

public class Garage {// Tries to start the passed Car.public void TryToStartCar(Car car) {

car.StartEngine();}

}

public class Car {// Trace message instead of implementation.public virtual void StartEngine() {

Console.WriteLine("Car::StartEngine()");}

}

public class VintageCar : Car {// Trace message instead of implementation.public override void StartEngine() {

Console.WriteLine("VintageCar::StartEngine()");}

}

?

?

Garage joesStation;Car seatLeon = new Car();VintageCar fordThinLizzie = new VintageCar();joesStation.TryToStartCar(seatLeon); // Should call Car's StartEngine().joesStation.TryToStartCar(fordThinLizzie); // Should call VintageCar's StartEngine() inherited from Car.

● Which implementation of StartEngine() will becalled?● Car's implementation?● VintageCar's implementation?

● Polymorphism:● In future the implementation of method

StartEngine() of any other sub type of Car couldbe called!

Page 11: (5) c sharp introduction_object_orientation_part_ii

11

Example for Polymorphism: Windows Forms Controls

public class Control { // (members hidden)public Size Size { get; set; }protected virtual void OnPaint() { /* pass */ }

}

public class Button : Control { // (members hidden)protected override void OnPaint() { /* pass */ }

}

public class ListBox : Control { // (members hidden)protected override void OnPaint() { /* pass */ }

}

● This is a simplified presentation of the hierarchy in the Windows Forms library.

● The base class Control defines common properties and methods:

– Size: Gets or sets the height and width of the control.

– OnPaint(): Draws the control on the screen.

● Then the specializations of Control, Button and ListBox

– inherit the property Size from Control, because each control has a Size and

– override the method OnPaint(), because each control draws itself differently.

– => Size is inherited and OnPaint() needs to be specialized.

● This is a simplified presentation of the realhierarchy in the Windows Forms library.

Page 12: (5) c sharp introduction_object_orientation_part_ii

12

Abstract Types

● There are types, which are too abstract to have instances.

– Some methods can not provide suitable virtual (default) implementations.

– E.g. maybe Car is too abstract of its own, we should not assume, that it has an Engine, or even a SpareTyre... it could be left away.

– Instead we can assume any Car has some (not necessarily four) Tyres.

– More concrete subtypes (as VintageCar) could have filled, what we left away in Car.

– Type Car is even too abstract to provide a default implementation StartEngine().

● Abstract types in C#:

– Types can implement some methods and others can be left (declared) abstract.

– Such types must be declared abstract itself, becoming abstract types.

– Only concrete subtypes of abstract types can be instantiated.

– A concrete type must implement all abstract methods of its base types.

● Abstract types:● How is it possible to have multiple base types?

● In C# a base type can derive from anotherbase type that has a further base type... Andas long our type does not implement all theabstract methods of these base types, we'veto declare our type also as abstract.

Page 13: (5) c sharp introduction_object_orientation_part_ii

13

Type Car revisited

● Here a simple abstract version of Car is presented, VintageCar is concrete!

public abstract class Car { // (member hidden)/// <summary>/// Here StartEngine() can not yet be defined concretely./// </summary>public abstract void StartEngine();

}

public class VintageCar : Car { // (member hidden)/// <summary>/// Here StartEngine() can be implemented somehow./// </summary>public override void StartEngine() { /*The implementation goes here.*/ }

}

● In this example the type Car is abstract.● The keyword abstract is used on Car's type

declaration and StartEngine()'s methoddeclaration. StartEngine() has noimplementation and it's implicitly virtual.

● VintageCar derives from Car. Additionally thekeyword override is used to override themethod StartEngine() in VintageCar. Theoverride provides an (empty) implementation.

Page 14: (5) c sharp introduction_object_orientation_part_ii

14

Why is Abstraction needed?

● OO programmers design models that simulate reality.

– Abstraction means to leave out irrelevant details from the model.

– Some degree of detail is sufficient. Capturing "all" details is impossible (computer memory, time and expert knowledge is limited).

– OO seems to be appropriate for big projects to get rid of the "academic touch".

● A vendor's framework only abstracts a certain (the vendor's) view of a model.

– Multiple abstraction solutions can be correct for a certain task.

● Delegation, information hiding, encapsulation and substitution help to abstract.

– This means do also help to postpone or defer details.

● A core idea of oo development is to accept types as incomplete.

– These types could be extended incrementally and iteratively.

● This is called incremental and iterative software engineering.

● Abstraction from lat. abstrahere: "to removesomething".

● What does "incremental and iterative" mean?● Incremental: the engineering will be performed

in steps.● Iterative: some parts of the engineering process

will be repeated to improve some aspects.

Page 15: (5) c sharp introduction_object_orientation_part_ii

15

Interfaces

● Some types do not only fulfill the base type's behavior, but other behaviors.

– The VintageCar is a Car but it is also a historical thing and should behave so.

– So we could introduce a new base type "Historical", because VintageCar is historical. Historical has the readonly properties Era and EstimatedPrize.

– But in .Net we can not let VintageCar inherit from more than one base type!

● Interfaces to the rescue!

– Historical's methods must be left abstract, each Historical type differs...

– The type Historical does rather define a behavior, than a complete type.

– Any type that behaves as Historical substitutes as subtypes do.

– In C# we can define Historical as interface to act as behavioral type.

– We can also understand an interface as a contract!

– interfaces contain only abstract methods, but no fields! A type can implement multiple interfaces, but can have only one base type!

– Important .Net interfaces: IComparable, IEnumerable, IDisposable etc.

● A good way to understand interfaces is to viewthem as concepts. Then the implementations ofinterfaces are just the implementations of theconcepts.

Page 16: (5) c sharp introduction_object_orientation_part_ii

16

Application of Historical Cars in UML Class Diagram

● VintageCar is a Car and implements or behaves IHistorical.

– VintageFurniture also implements IHistorical.

● As a convention in .Net the names of interfaces are prefixed with an "I".

● An interface can inherit from more than one interface (multiple inheritance).

Car

+ HasStarter() : bool+ StartEngine()

VintageCar

- CrankUntilStarted() : bool+ StartEngine()

<<interface>>

IHistorical

+ Era() : Era+ EstimatedPrize() : double

IHistorical is an interface. Mindthe italic header and the stereotype“interface” written in guillements.

VintageCar implements theinterface. Mind the triangular arrow-tipand the dashed line.

VintageFurniture

+ GetWoodType() : WoodType

Page 17: (5) c sharp introduction_object_orientation_part_ii

17

Implementation of Historical Cars in C# Code

● VintageCar is a Car and implements IHistorical. (Types Era and Car elided.)

public interface IHistorical {Era Era { get; }double EstimatedPrize { get; }

}

public class VintageCar : Car, IHistorical {private Era _theEra;private double _currentEstimation;

public VintageCar(double estimatedPrize) {_currentEstimation = estimatedPrize;

}

public Era Era {get {return _theEra;}

}public double EstimatedPrize {

get {return _currentEstimation;}}

}

public class VintageFurniture : IHistorical {private Era _theEra;private double _currentEstimation;

public VintageFurniture(double estimatedPrize) {_currentEstimation = estimatedPrize;

}

public Era Era {get {return _theEra;}

}public double EstimatedPrize {

get {return _currentEstimation;}}

}

● The interface IHistorical:● All methods and properties are implicitly public

and abstract.● The class VintageCar:

● VintageCar implements IHistorical.● In the type declaration the base type (Car)

specification must be positioned before any ofthe interfaces (IHistorical) specifications a subtype implements.

● The properties of the interface IHistorical thatare implemented by VintageCar mustn't bedeclared with the override keyword!

Page 18: (5) c sharp introduction_object_orientation_part_ii

18

The static and the dynamic Type of an Object

● Polymorphism allows that a reference can refer different types at run time.

● A reference has a static type and a dynamic type. For example in:

– The static type of the parameters h1 and h2 is IHistorical, so only methods of the interface IHistorical can be called, i.e. only typesthat fulfill the IHistorical contract!

– The dynamic types of references h1 and h2 can be any type that implements IHistorical respectively, so VintageCar, or any typeimplementing IHistorical in future!

– It is said that the usage of interfaces abstracts the usage of a type from its implementation. - h1 and h2 are just IHistoricals,whether those are VintageCars or VintageFurnitures doesn't matter!

● In .Net the dynamic type can be checked and navigated.

– Via object's method GetType(), the keywords is and as and "downcasting".

– But explicit dynamic type checking should be done rarely, use design patterns!

public double SumOfEstimatedPrices(IHistorical h1, IHistorical h2) {return h1.EstimatedPrice + h2.EstimatedPrice;

}

double sum = SumOfEstimatedPrices( // Two IHistoricals:new VintageCar(200000),new VintageFurniture(3999));

Page 19: (5) c sharp introduction_object_orientation_part_ii

19

Sealed Types

● There exist types, which mustn't be inherited!

– Because of the substitution principle, a UDT can replace its base type at run time!

– So we could derive from string and override the property Length, so that length would send an email with the string's content tosomeone else...

– Well, this must be controlled (and maybe forbidden) somehow.

● In C#, types and methods can be sealed to avoid undesired overriding.

– If a method was overriden, it can be sealed.

– A sealed type can not be inherited altogether (so does string). - This cuts off the substitutability of such a type, so it can not actas base type!

– For types that should be base types certain methods can be marked as being not overridable with the keyword sealed. =>sealed versus abstract

public class SealedCar : Car { // (member hidden)/// <summary>/// This implementation of StartEngine() can not be overridden./// </summary>public override sealed void StartEngine() { /* The implementation goes here. */ }

}

● The keyword sealed:● We've to write the keywords override and sealed

together on the method.● On a type we just use the sealed keyword

directly, then that type can not be used as basetype anymore.

Page 20: (5) c sharp introduction_object_orientation_part_ii

20

The SOLID Principle

● Robert Cecil Martin ("Uncle Bob") et al. collected five principles for oo design.

– These principles guide us through the design of "good" oo code.

● Single Responsibility Principle (SRP)

● Open-Close Principle (OCP)

● Liskov Substitution Principle (LSP)

● Interface Segregation Principle (ISP)

● Dependency Inversion Principle (DIP)

● SRP: Types should have only one reason to change. Thisrequirement also applies to methods.

● OCP: Open types for extension, but close them formodification, i.e. extend them w/o modification of the corecode, rather code will be added (e.g. via polymorphism). If weneed to modify a type's interface, the calling code needs to bemodified (ripple effect), which is expensive. Separate thingsthat change, from others that don't (i.e. find the vector ofchange to drive design patterns).

● LSP: Exploit subtyping to put the substitution principle intoeffect.

● ISP: Use small type interfaces to which callers depend on, sothat changes in other type interfaces don't bother them.

● DIP: Let types only depend on abstract types (the contracts),never on concrete types (the implementation) to reducecoupling. Layers of lower abstraction (more concrete type)depend on layers of higher abstraction (more abstract types),never vice versa.

● The SOLID principle enumerates a set of guidelines, not laws.

Page 21: (5) c sharp introduction_object_orientation_part_ii

21

Thank you!


Recommended