Objects can be considered as real-world instances of entities like class, that have some characteristics and behaviors.
Class
A blueprint or template for creating similar types of objects. They usually have:
Attributes or Data
Behaviors or Methods
Class Relationships
"is-a" relationship
class Animal // parent class
{
public virtual void Move() {
Console.WriteLine("i can move");
}
}
class Dog : Animal // child class inheritance
{
public override void Move() {
Console.WriteLine("i can run");
}
}
"has-a" relationship : can be one-to-many, many-to-one, many-to-many.
classes exist independently
class Customer
{
public string Name { get; set; }
public void PlaceOrder(Order order) // association
{
Console.WriteLine("Order Placed");
}
}
class Order
{
public Customer Customer { get; set; } // association
}
Aggregation
child class can exist independently of the parent class
class OrderItem // child class
{
public string Name { get; set; }
public int Quantity { get; set; }
}
class Order // parent class
{
private List<OrderItem> items = new List<OrderItems>(); // aggregation
public void AddItem(OrderItem item)
{
items.Add(item);
}
}
Composition
child class cannot exist independently of the parent class
class Engine // child class
{
public void Start() {
Console.WriteLine("Engine Started");
}
}
class Car // parent class
{
private Engine engine = new Engine(); // composition
public void Start() {
engine.Start();
}
}
Inheritance
A mechanism in which one class inherits the properties of another class.
Single Inheritance
Multilevel Inheritance
Hierarchical Inheritance
Hybrid Inheritance
class Parent { ... }
class Child1 : Parent { ... } // Single, Hierarchical
class Child2 : Parent { ... } // Hierarchical, Multilevel
class GrandChild : Child2 { ... } //Muiltilevel
interface Service1 { ... }
interface Service2 { ... }
class Child : Service1, Service2 { ... } // Multiple
class Parent:
class Child1(Parent): # Single, Hierarchical
class Child2(Parent): # Hierarchical, Multilevel
class GrandChild(Child2): # Multilevel
class Parent1:
class Parent2:
class Child(Parent1, Parent2): # Multiple
Polymorphism
A concept where an object behaves differently in different situations.
Compile-time Polymorphism / Static Dispatch
Function/Method/Operator Overloading a.k.a. Early Binding
With overloading you have a function with different sets of parameters. The function that is to be executed is determined using the number and type of the parameters you provide. As these are known at compile time, the compiler already determines the function to use. Because of this, it is called compile time polymorphism.
public class Calculate {
public int Add(int a, int b) {
return a + b;
}
public int Add(int a, int b, int c) { // Function Overloading
return a + b + c;
}
}
Runtime Polymorphism / Dynamic Dispatch
Method Overriding (virtual/abstract) a.k.a. Late Binding
When you are overriding a virtual function of a base class in one or more derived classes and then call this function from a base class, the actual class of the underlying object is not clear at compile time. Thus it is determined only at runtime which function is executed. That is why it is called runtime polymorphism.
public class Drawing {
public virtual double Area() {
return 0;
}
}
public class Circle : Drawing {
public double Radius { get; set; }
public Circle() {
Radius = 5;
}
public override double Area() { // Method Overriding
return (3.14) * Math.Pow(Radius, 2);
}
}
public class Square : Drawing {
public double Length { get; set; }
public Square() {
Length = 6;
}
public override double Area() { // Method Overriding
return Math.Pow(Length, 2);
}
}
public class Rectangle : Drawing {
public double Height { get; set; }
public double Width { get; set; }
public Rectangle() {
Height = 5.3;
Width = 3.4;
}
public override double Area() { // Method Overriding
return Height * Width;
}
}
class Program {
static void Main(string[] args) {
Drawing circle = new Circle(); // Late Binding
Console.WriteLine("Area :" + circle.Area());
Drawing square = new Square(); // Late Binding
Console.WriteLine("Area :" + square.Area());
Drawing rectangle = new Rectangle(); // Late Binding
Console.WriteLine("Area :" + rectangle.Area());
}
}
Abstraction
Abstraction is the process to hide the internal details and show only the functionality.
The keyword abstract is used before the class or method to declare the class or method as abstract.
An Abstract method is a method without a body.
The implementation of an abstract method is done by a derived class.
When the derived class inherits the abstract method from the abstract class, it must override the abstract method.
Abstraction is the concealment of unnecessary program details so that the user only sees the essential attributes.
The Abstract class and Interface both are used to have abstraction.
class program {
abstract class Animal {
public abstract void Eat();
public void Sound() {
Console.WriteLine("dog can sound");
}
}
class Dog : Animal {
public override void Eat() {
Console.WriteLine("dog can eat");
}
}
}
An Abstract class can have non-abstract Methods(concrete methods) and declare variables while in case of Interface all the methods has to be abstract and there should not be any implementation.
Encapsulation
Encapsulation refers to the bundling of data/properties with the methods that operate on that data, or the restricting of direct access to some of an object's components.
Encapsulation is used to hide the values or state of a structured data object inside a class, preventing direct access to them by clients in a way that could expose hidden implementation details or violate state invariance maintained by the methods.
Encapsulation is achieved by taking advantage of the access modifiers that include public, private protected, private, internal, and protected that control the visibility and accessibility of the members of a class.
Encapsulation is the bundling of data, including the methods that operate on that data, into a single, private unit
public class Account {
private string accountNumber;
private decimal balance;
public Account(string accountNumber, decimal balance) {
this.accountNumber = accountNumber;
this.balance = balance;
}
public decimal GetBalance() {
return balance;
}
public void Deposit(decimal amount) {
balance += amount;
}
public void Withdraw(decimal amount) {
if (balance >= amount)
balance -= amount;
}
}
In this example, the Account class has two private members: accountNumber and balance. These members are not accessible from outside the class. The class provides public methods GetBalance(), Deposit(), and Withdraw() to allow outside code to interact with the object.
How to Approach
Handle Ambiguity
Depending When being asked an object-oriented design question, you should inquire who is going to use it and how they are going to use it.
Depending on the question, you may even want to go through the "six W's": who, what, where, when, how, why