(5) c sharp introduction_object_orientation_part_ii

download (5) c sharp introduction_object_orientation_part_ii

If you can't read please download the document

description

This presentation comes with many additional notes (pdf): http://de.slideshare.net/nicolayludwig/5-c-sharp-introductionobjectorientationpartii-38639919 Check out these exercises: http://de.slideshare.net/nicolayludwig/5-c-sharp-introductionobjectorientationpartiiexercises - When to use Inheritance - Polymorphism - Abstraction - Abstract Types - Interfaces - Sealed Types - Static and dynamic Type of Objects

Transcript of (5) c sharp introduction_object_orientation_part_ii

  • 1. (5) Introduction of C# object-oriented Programming Part IINico Ludwig (@ersatzteilchen)

2. 2TOC (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 3. 3Everything 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. 4. 4Using Cars in Garages The class Garage and its implementation of the method TryToStartCar().public class Garage {Garage+ TryToStartCar(car : Car)/// /// Tries to start the passed Car./// /// The Car to start.public void TryToStartCar(Car car) {car.StartEngine();}} 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.)CarBusEngineGarage joesStation;Car seatLeon = new Car();Bus mercedesIntegro = new Bus();joesStation.TryToStartCar(seatLeon); // OK!joesStation.TryToStartCar(mercedesIntegro); // OK! 5. 5Intermezzo: 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). 6. 6When 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. 7. 7Polymorphism 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. 8. 8The VintageCar Example VintageCar can override Car's (VintageCar's base-type) method StartEngine().public class Car {/// /// Starts the Car, default implementation./// public virtual void StartEngine() {_theEngine.Start();}}public class VintageCar : Car {/// /// Starts the Car, special implementation for Cars with crank./// 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() 9. 9Polymorphism 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().// >CarCar bus = new Bus();Console.WriteLine(bus); // Calls Bus' special ToString().// >A Bus with 10 vacant seats. 10. 10Where is Polymorphism happening? Whose implementation of method StartEngine() is called in a Garage?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.public class Garage {// Tries to start the passed Car.public void TryToStartCar(Car car) {car.StartEngine();}} This is decided during run time polymorphically!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()");}}?? 11. 11Example for Polymorphism: Windows Forms Controls This is a simplified presentation of the hierarchy in the Windows Forms library.public class Control { // (members hidden)public Size Size { get; set; }protected virtual void OnPaint() { /* pass */ }} The base class Control defines common properties and methods:public class Button : Control { // (members hidden)protected override void OnPaint() { /* pass */ }}public class ListBox : Control { // (members hidden)protected override void OnPaint() { /* pass */ }} 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. 12. 12Abstract 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. 13. 13Type Car revisited Here a simple abstract version of Car is presented, VintageCar is concrete!public abstract class Car { // (member hidden)/// /// Here StartEngine() can not yet be defined concretely./// public abstract void StartEngine();}public class VintageCar : Car { // (member hidden)/// /// Here StartEngine() can be implemented somehow./// public override void StartEngine() { /*The implementation goes here.*/ }} 14. 14Why 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. 15. 15Interfaces 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 andEstimatedPrize. 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. 16. 16Application 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()IHistorical+ Era() : Era+ EstimatedPrize() : doubleIHistorical is an interface. Mindthe italic header and the stereotypeinterface written in guillements.VintageCar implements theinterface. Mind the triangular arrow-tipand the dashed line.VintageFurniture+ GetWoodType() : WoodType 17. 17Implementation 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;}}} 18. double sum = SumOfEstimatedPrices( // Two IHistoricals:18The 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:public double SumOfEstimatedPrices(IHistorical h1, IHistorical h2) {return h1.EstimatedPrice + h2.EstimatedPrice;} 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!new VintageCar(200000),new VintageFurniture(3999)); 19. 19Sealed 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. => sealedversus abstractpublic class SealedCar : Car { // (member hidden)/// /// This implementation of StartEngine() can not be overridden./// public override sealed void StartEngine() { /* The implementation goes here. */ }} 20. 20The 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) 21. 21Thank you!