Welcome to the second episode of my course “Becoming a software developer”, which will focus on the other important parts of the OOP such as inheritance, polymorphism, interfaces and abstractions.
All of the materials including videos and sample projects can be downloaded from here.
If you’re not familiar with the previous episode about one of the core concepts of the OOP (Object Oriented Programming) which is modeling the proper classes, please click here.
Scope
This episode will finish our journey related to the basics of OOP, we will discuss the following topics:
- Inheritance
- Polymorphis
- Interfaces
- Abstractions in general
Abstract
Inheritance is an important concept as it lets you derive from properties and methods of your base class (the one that you inherit from). This is also where the protected modifier comes in handy – it acts as a private one, however you can still access protected properties and methods in a derived class – if you were to use private in your base class you could not do that. The general rule is that you should not use inheritance too often, but if you do, make sure you have 1, max 2 levels of inheritance – otherwise you’ll make a “tree” and it will be a source of potential issues.
Personally, I make use of the inheritance for defining the base classes that I’m using in multiple places and I’m 100% certain that I’ll need all of its properties in my child classes – if you feel like it’s a good idea to design a base class, where half of its properties will be needed for one class and the other half for another class, drop such idea instantly.
For example, I would have a base class designed for pagination containing Page and ResultsPerPage properties that I could derive from in order to make the child classes specialized for loading the paginated data from a database for distinct types like Users, Orders, Products and so on. Just remember this – do not use inheritance too often unless you’re certain that you’ll need it. And if you do, make sure that all of the base properties and/or methods will be needed for the child classes, which is usually the reason why the base classes tend to be rather small.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public abstract class Car { public double Aceeleration { get; protected set; } = 10; public double Speed { get; protected set; } = 100; public void Start() { Console.WriteLine("Turning on the engine..."); Console.WriteLine($"Running at: {Speed} km/h."); } public void Stop() { Console.WriteLine("Stopping the car..."); } } public class Truck : Car { } public class SportCar : Car { } |
With inheritance (but not only) comes the polymorphism. Let’s say you have the base User class from which derive the Administrator and Moderator.
In your code, you could, for example, specify a method or a collection (or anything else that comes into your mind) that would take as an argument/be of type User which is a base class, and then pass to such function or collection the instances of Administrator or Moderator. Why would you do so? Because you can treat your child classes as they are their parents (and yes, they are as they inherit from them) and make use of all the common properties or functions of the parent class.
Let’s take a very common example – there’s a base class Car and it has multiple children like Truck, SportCar, Sedan etc. In your base Car class you can define a property like Color or method like StartEngine() and then access it from all of the actual types of cars (child classes) simply by making some particular method take an instance of the Car base class. It’s quite similar to using interfaces as the method parameters or types, where all you care about is that a provided instance has to be of the base class type (or inherit from it), which in result allows you to access all of its properties and methods without realizing what’s the actual type provided (whether it’s Sedan, Truck or SportCar).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
public abstract class Car { public double Aceeleration { get; protected set; } = 10; public double Speed { get; protected set; } = 100; public void Start() { Console.WriteLine("Turning on the engine..."); Console.WriteLine($"Running at: {Speed} km/h."); } public void Stop() { Console.WriteLine("Stopping the car..."); } public virtual void Accelerate() { Console.WriteLine("Accelerating..."); Speed += Aceeleration; Console.WriteLine($"Running at: {Speed} km/h."); } public abstract void Boost(); } public class Truck : Car { public override void Accelerate() { Console.WriteLine("Accelerating a truck..."); base.Accelerate(); } public override void Boost() { Console.WriteLine("Boosting a truck..."); Speed += 50; Console.WriteLine($"Running at: {Speed} km/h."); } } public class SportCar : Car { public override void Accelerate() { Console.WriteLine("Accelerating a sport car..."); base.Accelerate(); } public override void Boost() { Console.WriteLine("Boosting a sport car..."); Speed += 100; Console.WriteLine($"Running at: {Speed} km/h."); } public void DisplayInfo() { Console.WriteLine("Sport car."); } } |
Interfaces may seem as a useless thingy at the first glance. It turns out, that they’re one of the most powerful ones. Whenever you work with classes and these classes make use of the other classes (passed via constructor or methods) you’re increasing a complexity of your system.
It’s called tight coupling and low cohesion, and what you should strive for are loose coupling and high cohesion.
Think about this – you have a class responsible for connecting to the database or sending emails. And there’s another class for processing the orders, that makes use of the previous 2 classes – it has to fetch an order from the database, process it, and then send an email. In that case, you would pass these 2 classes as parameters via constructor to the processing orders class. But what if you would like to skip sending email part? Maybe display a console output that it was sent without actually sending it?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
public interface IEmailSender { void SendMessage(string receiver, string title, string message); } public interface IDatabase { bool IsConnected { get; } void Connect(); User GetUser(string email); Order GetOrder(int id); void SaveChanges(); } public interface IOrderProcessor { void ProcessOrder(string email, int orderId); } public class OrderProcessor : IOrderProcessor { private readonly IDatabase _database; private readonly IEmailSender _emailSender; public OrderProcessor(IDatabase database, IEmailSender emailSender) { _database = database; _emailSender = emailSender; } public void ProcessOrder(string email, int orderId) { User user = _database.GetUser(email); //Fetch from db Order order = _database.GetOrder(orderId); //Fetch from db user.PurchaseOrder(order); _database.SaveChanges(); _emailSender.SendMessage(email, "Order purchased", "You've purchased an order."); } } |
Or what if instead of talking to the database, you would like to provide a “fake” collection that works on the list or array in memory? Not to mention that there’s no way to write tests for such code. And this is what you need interfaces for. They define a so-called contract which means that all of the properties and methods are public for the interface consumer.
1 2 3 4 5 6 7 8 9 |
public class FakeEmailSender : IEmailSender { //Implement this interface. } public class FakeDatabase : IDatabase { //Implement this interface. } |
Therefore, if you pass the interface via constructor or method and operate on the interface (which under the hood has to be implemented by some class, but you don’t care about this class), you can easily switch e.g. from the real mailing service to the fake one writing console output etc. You can also test such code easily. Would you really like to go to the shop, buy a new keyboard and have to deal with some weird cables and plugs (your tightly coupled classes) instead of using the USB (interface)?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class Shop { public void CompleteOrder() { IDatabase database = new Database(); IEmailSender emailSender = new EmailSender(); IOrderProcessor orderProcessor = new OrderProcessor(database, emailSender); orderProcessor.ProcessOrder("user1@email.com", 1); } public void CompletFakeOrder() { IDatabase database = new FakeDatabase(); IEmailSender emailSender = new FakeEmailSender(); IOrderProcessor orderProcessor = new OrderProcessor(database, emailSender); orderProcessor.ProcessOrder("user1@email.com", 1); } } |
And this is why we have to strive for abstractions. In order to make maintainable, extendable and testable code. If you won’t use interfaces for designing the contracts of your business logic classes and other important parts of the application that should be easily replaceable (and testable) you will make a so tightly coupled system, that changing class A might affect changing classes B and C and changing these 2 might lead to changing other ones and… you see where I’m going at with this chain of highly possible disaster. In the future episodes, you’ll see how to use interfaces in a real world application once we get into some very cool patterns like Dependency Injection using IoC (Inversion of Control) Container and how the interfaces are the only way to make your codebase truly testable.
Resources
- http://www.infoworld.com/article/2928719/c-sharp/my-two-cents-on-abstract-class-vs-interface.html
- http://stackoverflow.com/questions/7325518/whats-the-difference-between-inheritance-and-polymorphism
- https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms173152(v=vs.100).aspx
- http://csharp-station.com/Tutorial/CSharp/Lesson09
- http://www.akadia.com/services/dotnet_polymorphism.html
- http://www.infoworld.com/article/3024718/application-development/how-to-implement-polymorphism-in-c.html
- http://csharp-station.com/Tutorial/CSharp/Lesson13
- https://www.quora.com/What-are-some-real-world-example-of-encapsulation-and-abstraction-and-how-are-they-different-yet-related
- https://www.onlinebuff.com/article_oops-principle-abstraction-in-c-with-an-example-and-explanation_5.html
- http://stackoverflow.com/questions/16938667/how-abstraction-and-encapsulation-differ
- http://www.c-sharpcorner.com/uploadfile/4624e9/abstraction-in-C-Sharp/
- https://dzone.com/articles/c-interfaces-what-are-they-and
- http://www.aspneto.com/oop-concepts-object-oriented-programming-concepts-with-examples.html
Next
In the next episode, we’ll jump right into a little bit more advanced topics. We’ll talk about the following keywords and concepts:
- Exceptions
- Generics
- var
As usual, make sure that you’ll do your own research first about the listed stuff. In short, you will learn how to deal with errors occurring as exceptions and how useful the generics are. Next, you’ll find out how to make use of the var keyword in order to reduce an amount of unnecessary code and declare anonymous objects – so see you next week!
Pingback: Becoming a software developer – episode II – Patryk Huzarski | Personal Blog
zajebiste!
wincyj! wincyj!
Dzięki, będzie wincyj, już za tydzień odcinek nr 3 :D.
Pingback: Dew Drop - February 2, 2017 (#2413) - Morning Dew
..już się nie mogę doczekać:)
Będzie warto ;).
Co mi się podoba w Twoim kursie ? Przykłady z życia (programisty) wzięte. Sam jestem na etapie uczenia się (głównie książki), gdzie jak się domyślasz podana jest sucha teoria z marnym przykładem. Efekt tego nijaki…siadam do pisania własnej aplikacji i co ?! Szperam na forach jakiej składnie użyć bo co w książce było to już zapomniałem albo nie znalazłem tam odpowiedniego przykładu.
Do mnie zdecydowanie przemawia Twoje podejście do kursu.
Właśnie taki jest główny cel kursu, gdyż dokładnie wiem jak to jest uczyć się wszystkiego na własną rękę, zastanawiać się jaki wzorzec jest poprawny, a jaki nie itd. Całość powinna być naprawdę interesująca w momencie gdy przejdę już do omawiania wzorców, architektury i następnie zaczniemy wdrażać wszystko to co zostało poznane do budowy aplikacji.
Cieszę się, że trafiłem w gusta kolejnej osoby :).
Cześć, super realistyczny kurs!!
Ps. Jak zwiększyć rozdzielczość??
Hej, dzięki!
Co masz na myśli odnośnie rozdzielczości? Jeżeli chodzi o filmik to najlepiej wybrać 4k w ustawieniach odtwarzacza na YouTube, a poza tym można wszystkie materiały pobrać tutaj: https://bit.ly/basd-course.
Hej
Do tej pory korzystałem jedynie z telefonu do oglądania episod’ów, a tam nie ma opcji zmiany rozdzielczość :/. Na komputerze jest ok.
Cześć, no niestety ale oglądanie kursów na telefonie IMO mija się z celem, bo nawet przy 5 calowym ekranie i mniejszej rozdzielczości nagrywania nie jest to zbyt komfortowe.
Hej, używałem telefonu jako źródła dla TV;) podczas zabaw z dzieckiem;)
Na Yt jest już ok.
Ps. Będzie w którymś z epizodów mvc mvvm??
pozdrawiam
Cześć, o MVVM nie, bo to nie ma nic wspólnego z webem (co najwyżej we front-endzie). MVC jako tako tzn. będziemy tworzyć aplikację webową ale sam backend HTTP API i do tego raczej nie będą dorabiane widoki.
Cześć,
Czy ‘przypadkiem’ nie wprowadziłeś nam wzorca projektowego Template Method, gdy pracowałeś na pliku Car.cs? Mamy główną klasę abstrakcyjną i x podklas. (x oznacza rodzaj pojazdu, czyli np. ciągnik, samochód, ciężarówka itd. itp.)
Można teraz tworzyć nowe klasy z szablonu (np Van), tylko trzeba później dodać w klasie Race ich inicjalizację.
To jest ten wzorzec, czy coś pomąciłem? 😉
Cześć, bardzo możliwe, chociaż powiem szczerze, że w momencie gdy tworzyłem ten przykład zupełnie nie myślałem o nim pod kątem wspomnianego wzorca :).
Pingback: Dew Drop – February 2, 2017 (#2413) (by Alvin A.) - ugurak.net