The keyword specifies that the base class is to be used and provides access to its methods, constructors, and member variables. Using base.field we can get the value of a member variable from the base class or assign another one to it. In .NET, methods inherited from the base class and declared virtual can be overridden.
Non-overridden methods can be called from the base class without using the base keyword. It clearly explains which members of the base class (methods, constructors, and member variables) are accessible. When inheriting a class, our constructors must call the constructor of the base class so that it can initialize its member variables.
If the base class does not have a default (no-parameter) constructor, or if that constructor is hidden, our constructors must explicitly call one of the other base class constructors. All its internal members are visible to the inheriting class only if the base class and the inheriting class are in the same composition (the same Visual Studio project).
Overriding ToString() – Example
When we pass an object to the WriteLine() method, that object provides its string representation using ToString() and only then is it printed to the output stream. We notice that the implementation of Object.ToString() is invoked when we send AfricanLion to object. In other words, when we use the keyword new, we create a new method that hides the old one.
What would happen if we went back to using the "override" keyword in the previous example. It turns out that when we override a method, we can't access the old implementation even if we use upcasting. If we want a method to be overridable, we can do so by including the virtual keyword in the method declaration.
If there is a typo in the method name or parameter types, the compiler will notify us. It will know something is wrong if it can't find a method with the same signature in one of the base classes.
Transitive Properties of Inheritance
Transitiveness – Example
Inheritance Hierarchy
Class Diagrams
What is UML Class Diagram?
A Class Based on a Class Diagram – Example This is what a sample class diagram looks like
Class Diagram – Example of Generalization
Associations
From Diagrams to Classes
Capital.cs public class Capital { }
Aggregation
Composition
Abstraction
It allows us to write code that works with abstract data structures (like dictionaries, lists, arrays, and others). We can work with an abstract data type by using its interface without worrying about the implementation. For example, we can store all elements of a list in a file without worrying if it is implemented with an array, a linked list, etc.
We can even write new data types (we'll discuss this later) and make them work with our program without changing it. When we combine this with the ability to work with abstract data, we achieve great flexibility in integrating these small programs and many more opportunities for code reuse. This approach to writing programs is widely adopted because it allows us to reuse not only objects, but also entire subprograms.
Abstraction – Abstract Data Example
Interfaces
Some may ask why the base class of all objects (the Object class) is not an interface. The reason is that in this case each class would have to implement a small but very important group of methods, which would take an unnecessary amount of time. It turns out that not all classes need a specific implementation of Object.GetHashCode(), Object.Equals.
There is no need to override any of the methods in the Object class, but if the situation requires it, we can.
Interfaces – Key Concepts
Interfaces – Example
The interface we wrote has a method of type T (T must inherit Felidae) which returns an array of T. The name of the interface is encoded in the class declaration (on the first line) and specifies the generic class. In an interface, methods are declared only; the implementation is coded in the class that implements the interface, i.e.
Abstraction and Interfaces
Some important Common Type System (CTS) interfaces are list and collection interfaces: System.Collections.Generic.IList
When Should We Use Abstraction and Interfaces?
When Should We Write Interfaces?
Encapsulation
Encapsulation – Examples
However, the implementation calls another method, which is hidden from the users of the class. This makes it possible to change its implementation at a later stage without any of the other classes finding out and needing changes.
Polymorphism
Abstract Classes
Abstract Class – Examples
Notice how in the example above, the normal Hide() and Run() methods have a body, but the abstract CatchPrey() method does not. Here is another example of abstract behavior implemented with an abstract class and a polymorphic abstract method call. In this case, we define an abstract method and later override it in the child class.
In the example, the PrintInformation() method from the abstract class does its job by relying on the result of a call to the abstract GetTypicalSound() method that is expected to be implemented in various ways by.
Purely Abstract Classes
Virtual Methods
Virtual Methods – Example
Different animals make different sounds, but the functionality for printing information about animals is common to all animals, and that is why it is exported in the base class. In the last attempt, you can clearly see that it is, in fact, called the overridden method and not the base method. This is because it verifies what the actual class behind the variable is and whether it implements (overwrites) that method.
Virtual Methods and Methods Hiding
The Difference between Virtual and Non-Virtual Methods
When Should We Use Polymorphism?
Cohesion and Coupling
Cohesion
Strong Cohesion
Strong Cohesion in a Class
Strong Cohesion in a Class – Example
Strong Cohesion in a Method
Weak Cohesion
Weak Cohesion – Example
Best Practices with Cohesion
Coupling
Loose Coupling
Loose Coupling – Example
Tight Coupling
Tight Coupling – Example
Such code is difficult to understand and maintain, and the likelihood of errors while using it is high. Consider what happens if another method, which calls Sqrt(), passes its parameters through the same static variable operand and result. If we need to use the same functionality for extracting the square root in a later project, we will not be able to simply copy the Sqrt() method, but will have to copy the MathParams and MathUtil classes along with all their methods .
In fact, the above code is an example of bad code by all rules of procedural and object-oriented programming and if you think twice, you will surely identify at least several more outrageous recommendations than those we have given you so far has.
Best Practices with Coupling
Using inner classes, which are not part of a module's public interface, is not recommended because their implementation can be replaced without replacing the contract (we have already discussed this in the "Abstraction" section). It is good practice that the methods are made flexible and ready to work with all components that observe their interfaces, and not just final components (i.e. have implicit requirements). The latter would mean that these methods expect something specific from the components they can work with.
A good example of strong cohesion and loose coupling is found in classes from the standard System.Collections and System.Collections.Generic namespaces. All non-interface methods and fields are hidden to reduce the possibility of linking to them. Methods in collection classes are independent of static variables and do not rely on any input other than their internal state and passed parameters.
Spaghetti Code
Cohesion and Coupling in Engineering Disciplines
Object-Oriented Modeling (OOM)
In object-oriented modeling, the model is created using OOP: through classes, class attributes, class methods, objects, relationships between classes, etc.
Steps in Object-Oriented Modeling
Identification of Classes
Identification of Class Attributes
Identification of Operations on Classes
Identification of Relationships between Classes
UML Notation
Use Case Diagrams
Use Case Diagrams – Example
The actor ("dwarf" in the diagram) is someone who interacts with the system (a user, external system or, for example, an external environment). A use case (“egg” in the diagram) describes a single functionality of the system, a single action that can be performed by several actors.
Sequence Diagrams
Sequence Diagrams – Example
Messages – Example
Statechart Diagrams
Design Patterns
This is one of the few books in the field of computer science that is still relevant 15 years after publication. Design patterns complement the basic principles of OOP with known solutions to known problems. You can also consult the "Data & Object Factory" pattern catalog http://www.dofactory.com/Patterns/Patterns.aspx, where the authors provide C# implementation of the classic GoF patterns.
The Singleton Design Pattern
The Singleton Design Pattern – Example
The pattern can undergo many optimizations, such as the so-called "lazy initialization" of the only variable, to save memory, but this is its classic form.
The Factory Method Design Pattern
The Factory Method Design Pattern – Example
Other Design Patterns
Exercises
Using Visual Studio, create class diagrams of the classes from the previous task with it. The bank has different types of accounts for its customers: deposit accounts, loan accounts and mortgage accounts. Loan accounts do not bear interest for the first 3 months if they are held by individuals and the first 2 months if they are held by companies.
Mortgage accounts have ½ interest rate for companies for the first 12 months and no interest rate for the first 6 months for individuals. You need to identify classes, interfaces, base classes and abstract actions and implement the interest calculation function.
Solutions and Guidelines