Saturday, April 17, 2021

What is the difference between Abstract Class and Interface in C#?


This is a very important question for interviews at all levels.

Common differences to remember,

  • An abstract class is a half defined class, Interface is fully abstract
  • An abstract class does not provide full abstract implementation but the Interface does
  • Multiple inheritances of an abstract class are not allowed but multiple interfaces are allowed
  • An abstract class can contain a method with implementation and fields but Interfaces are only allowed to declare methods and properties.
  • Access modifiers can be defined in an abstract class but Interface is by default public
  • An abstract class and methods require Abstract keyword to declare whereas in Interface it is Interface
  • In other words, an abstract class does not provide full abstraction but an Interface does

Common points to remember,

  • We can not create an object of both Abstract class and an Interface
  • An abstract class with all abstract member are similar to an Interface declaration

I hope this basic differences and common characteristics help you to understand the basics of both an Abstract class and an Interface.

For more details, you are welcome to visit the dedicated posts for each topic as given below,

Any doubts, confusion? feel free to drop your thoughts. 

Saturday, April 10, 2021

What is difference between Abstraction and Encapsulation?

Abstraction is about showing what is necessary to the client

Encapsulation is about hiding the complexity

Key Differences

  • Abstraction is about to show the only necessary, Encapsulation is about hiding complexity 
  • Abstraction is focusing on what to be done, Encapsulation is focusing on how it can be done.
  • Abstraction solves problems at the design level while Encapsulation solves problems at the implementation level
  • Abstraction can be achieved using Interface or Abstract class, Encapsulation is achieved through Access Modifiers (Private, Public, Protected, etc.)
  • Abstraction is to be achieved during the design level, while Encapsulation is achieved at the implementation level.

Importance of Abstraction

  • Abstraction imposes simplicity in the code
  • It hides the irrelevant details
  • Programmed can be partitioned into a different level and helps decouple the architecture
  • Provides flexibility across different types of objects

Importance of Encapsulation

  • Makes code more manageable and easy to change with new requirements
  • Makes coding easier by hiding the complexity to the client
  • This makes unit testing easy
  • It helps to change part of code rather than changing everything 
  • Makes code more readable and understandable to the client what it offers 


Thursday, April 8, 2021

SOLID | Dependency Inversion Principle (DIP)

 The dependency Inversion Principle, it states high level modules should not depend on low level modules. This is introduced by Robert C. Martin. 

Points to remember, 

  • High level and low level modules should depend upon abstractions 
  • and abstraction should not directly be dependent on the details but details should depend upon abstractions
  • Normally we have seen a project structure like
    • Presentation Layer - Business Layer - Data Access Layer (This is highly coupled) 
    • But introducing this principle suggests going with High Level Modules - Abstractions - Low Level Modules (This makes it loosely coupled)
    • So any changes to Low level should not affect directly to high level modules

Example,

will go first with Presentation Layer - Business Layer - Data Access Layer so,

public class BusinessLayer
{
        private DataAccessLayer dataAccessLayer;
        public BusinessLayer()
        {
                dataAccessLayer = new DataAccessLayer();
        }
        public void Save()
        {
                dataAccessLayer.Save();    
        }

public class DataAccessLayer
{
        public void Save()
        {
            //Method implementation
        }
}

Now, following the example, you see it is a strongly coupled and dependent architecture. Any change coming to DataAccessLayer would affect the existing implementation. 

In place, if we introduce another layer like Repository that acts as an abstraction to make this module a decoupled one. 

public class BusinessLayer
{
        //private DataAccessLayer dataAccessLayer;    This is commented to implement the abstraction
        private IRepositoryLayer repositoryLayer;
        public BusinessLayer(IRepositoryLayer repo)
        {
                repositoryLayer = repo;
        }
        public void Save()
        {
                repositoryLayer.Save();    
        }

public class DataAccessLayer : IRepositoryLayer        
{
        public void Save()
        {
            //Method implementation
        }
}

public interface IRepositoryLayer
{
        void Save();
}

Now, this works great to implement the Dependency Inversion Principle, We have inverted the dependency directly to an abstract layer, so both are loosely coupled, and if any change is coming up then it can be easily modified and even this makes unit testing the code more easily. 

In conclusion, as this is the last from SOLID principles, we have come across the basics of it and understanding with real world scenarios and examples. I hope anyone at glance would be able to grasp the foundation of principles. 

Any doubts or suggestions or thoughts are completely welcome, let me know if you want to know more in such simple language and examples. 

SOLID | Interface Segregation Principle (ISP)

Interface Segregation Principle (ISP), states "Clients should not be forced to depend upon interfaces that they do not use"

This is again introduced by Sir Robert D. Martin, while consulting at xerox.

Similar to the 

Single Responsibility Principle the goal of the Interface Segregation Principle is to reduce the side effects of frequent changes in the existing implementation. 

Points to remember,

  • No client needs to be forced to introduce with what is not necessary to them
  • Rather than using one fat interface, splitting into smaller and relevant interfaces are advisable

Case Study from Xerox,

  • Xerox created inhouse software to help printer system do tasks like stapling and faxing along with regular printer task
  • The whole system requires change from scratch up
  • That creates a whole lot of change and complexity

Example,

Below the interface is a one fat consisting of all the methods, now if something needs to introduce the whole implementation requires change and that is risky.

interface IPrint
{
        void Print();
        void Scan();
        void Fax();
}

We have solved this issue by separating SendEmail functionality from other classes to meet the Single Responsibility Principle.

The solution for the above example would,

interface IPrint
{
        void Print();
        void Scan();
}
interface IFax
{
        void Fax();
}

class Printer1: IPrint            //Only has the ability to Print 
{
        public void Print()
        {

        }
        public void Scan()
        {

        }

class Printer2: IPrint, IFax    //Printer ability to Print and Fax both
{
         public void Print()
        {

        }
        public void Scan()
        {

        }
         public void Fax()
        {

        }

We have separated the functionality by breaking it into interfaces rather than a single one. Now in Print1 that has the functionality of Print and Scan but not Fax so implementation, only IPrint interface will meet the goal. Printer2 is all in one so Print, Scan, and Fax functionality so along with IPrint we can have IFax interface to get the functionality of Fax in the same. 

Here we have separated the responsibilities as well as distributed the interface from a big fat to multiple interfaces and achieved a high level of abstraction.

SOLID | Liskov Substitution Principle (LSP)

Liskov Substitution Principle is introduced by Barbara Liskov. It is basically about the parent-child relationship (Inheritance) in Object-Oriented Design. the LSP states that if "When class S is a substitute of class T then an object of type T can be replaced by an object of type S without affecting the functionality of the existing implementation"

Points to remember,

  • Types can be replaced by their subtypes without altering the desirable properties of the program. 
  • It has often been related to a duck test, it says "If it is lookalike a duck, quacks like a duck, but needs batteries - you probably have the wrong abstraction"
  • Derived classes should be able to extend their base classes without altering the original implementation.

Example from previous posts,

public interface IEmployee
{
        void CalculateSalary(Employee employee);
}

public class PermenentEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class ContractEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class TemporaryEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class InternEmployee: IEmployee                                    //InternType with Error
{
         public void CalculateSalary(Employee employee)
        {
            throw new NotImplementedException();                        //Violation of LSP 
        }
}

So here is a good example of the Open Closed Principle, but if we are talking about the Liskov then we are breaking our goal here. For example what if a new requirement suggests a new Employee type without the CalculateSalary method. Say we have an Intern type to be added in. Class InternEmployee needs to throw an exception as it does not have to do anything with that method. 

Modified example with Liskov Substitution Principle,

public abstract class Employee                                                    //Abstract class 
{
        public virtual void CalculateSalary(Employee employee)
        {
          
        }
}

public class PermenentEmployee: Employee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class ContractEmployee: Employee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class TemporaryEmployee: Employee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}

public class InternEmployee: Employee
{
         //public void CalculateSalary(Employee employee)        //Not required to implement the same.
}

This is the example can have much more use of object oriented programming and I am stretching the same with other design patterns going forward in further posts. I will be explaining the alternative for Virtual method in base class. 

Happy learning!

Tuesday, April 6, 2021

SOLID | Open Closed Principle (OCP)

Open Closed Principle (OCP)

A class can be open for extension and closed for modification. 

Points to remember,  
  • Software needs to be flexible, saying that it should have the ability to accept the various changes
  • OCP helps to make application flexible enough to accept the new behavior rather than changing the old one
  • So new implementation would go in new classes and logic but nothing can be changed in the existing implementation
  • Helps to maintain the code easily without breaking the whole thing
  • The best way to remember is an electric adapter in your wall, once fitted it's close for modification but open for extension using an external adapter. 

Example with initial implementation of Employee class,

public class Employee
{
        public void CalculateSalary(Employee employee)
        {
              if(employee.Type == "Permenent")
                    //Salary calculation and print the same
              else if(employee.Type == "Contract")
                    //Salary calculation and print the same
        }
}

Now, the above class looks great as it has an Employee and it calculates salary based on their type of Permanent and Contract. And because it is not following the open closed principle adding a new EmployeeType would require a whole class to be changed. 

Now, Thinking the same example with Open Closed Principle,

public interface IEmployee
{
        void CalculateSalary(Employee employee);
}

public class PermenentEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class ContractEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class TemporaryEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}

Now, we have created an Interface and whole new classes to have the ability to create new Employee Types rather than changing the class all the time. Modifying existing implementation would not be a good idea at all. 

The interface IEmployee shares a common contract and that can be shared across derived classes. Now in this example also has a loop whole, let me know if you can find it another way. 

Why use the Open Closed principle?    

  • Software needs flexibility to change, and as per the above example if requirements are quite extending the same functionality then we can have a better approach toward the open-closed principle
  • It is also breaking another first princple of SOlID that is Single Responsibility, The above class had a multiple responsibility and we have devided that into their own territory so in future if anything comes up, no modification will be done in existing code
  • Maintenance becomes more convenient   

In conclusion, I would say, Open Closed Principle also requires implementation of Single Responsibility Principle, Breaking responsibilities from a single entity, and making a framework in a way that is open for extension and closed for modification meets the goal. 

Monday, April 5, 2021

SOLID | Single Responsibility Principle (SRP)

Single Responsibility Principle (SRP)

Introduced by Robert C. Martin, defines responsibility as a single reason to change the class.
  • A class should have only one job to do
  • It should have a single purpose to serve
  • By a single purpose and responsibility it does not mean to be a small class with limited members in it, it can have many but it should point to a single purpose. 
  • It helps to separate the classes at the first design phase so that the complexity can be reduced and can be more extensible

Example,

public class UserService
{
    //Create user
   public void CreateNewUser()
   {
        //New user creation implementation
        //Send an email alert
        SendEmail();
    }

    //Sending an email with user-created
    public void SendEmail()
    {
        //Email sending implementation
    }
}

A developer would only be able to understand only when he or she has a clear picture of what needs to be implemented according to the requirement. 

The above example shows two methods kind of user registration which registers the user and sends an alert email. The implementation is short and sweet to understand and it looks good at the first level. But as we are looking at the single responsibility principle you can have an idea of what is wrong with it. 

Let's redesign that with Single Responsibility Principle, 

public class UserService
{
    //Create user
   public void CreateNewUser()
   {
        //New user creation implementation
        
        //Send an email alert
        EmailService.SendEmail();
    }
}

public static class EmailService
{
    //Sending an email with user-created
    public void SendEmail()
    {
        //Email sending implementation
    }
}

Now, we have created a separate class for EmailService which can only contain email-related methods. UserService should have user related tasks in it. If SendEmail() method is part of the same service then at any other service if it needs to consume it would be a redundant code. At this level the same thing becomes reusable.
 

C# Interview Prep: 100 Common Questions for 0-3 Years Experience

Common C# Interview Questions  Basics of C# Language: What is C#? C# (pronounced C sharp) is a modern, object-oriented programming language...