Thursday, September 3, 2020

Interfaces

  • Interface contains declaration of methods, properties, events and indexers. 
  • public interface ITaxCalculator
    {
     int Calculate();
    }
    
  • Members of an interface do not have access modifiers and can not declare variables in the interface because fields are about the implementation details. 
  • Interfaces help building loosely coupled applications. We reduce the coupling between two classes by putting an interface between them. This way, if one of these classes changes, it will have no impact on the class that is dependent on that (as long as the interface is kept the same).
Interface and Testability
  • In order to unit test a class, we need to isolate it. This means: we need to assume that every other class in our application is working properly and see if the class under test is working as expected. But in below example, OrderProcessor class is depended on the ShippingCalculator class because of "CalculateShipping" method in "Process" method.
  •     public class Shipment
        {
            public DateTime shippingdate;
            public object cost { get; set; }
        }
    
        public class Order
        {
            public Shipment Shipment;
            public bool IsShipped { get { return Shipment != null; }}
            public DateTime DatePlaced { get; set; }
            public float TotalProce { get; set; }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var orderprocessor = new OrderProcessor();
                var order = new Order { DatePlaced = DateTime.Now, TotalProce = 100f };
                orderprocessor.Process(order); 
            }
        }
    	
        public class OrderProcessor
         {
            private readonly ShippingCalculator _shippingCalculator;
    
            public OrderProcessor()
            {
                _shippingCalculator = new ShippingCalculator();
            }
    
            public void Process(Order order)
            {
                if (order.IsShipped)
                {
                    throw new InvalidOperationException("The order already is shipped");
                }
    
                order.Shipment = new Shipment
                {
    		//Depend on the ShippingCalculator class
                    cost = _shippingCalculator.CalculateShipping(order),
                    shippingdate = DateTime.Now.AddDays(1)
                };
            }
        }
    	
        public class ShippingCalculator
        {
            public float CalculateShipping(Order order)
            {
                if (order.TotalProce > 30f)
                {
                    return order.TotalProce * 0.01f;
                }
                return 0;
            }
        }
    	
    
  • A class that has tight dependencies to other classes cannot be isolated. To solve this problem, we should use an interface. (The changes are in bold)
  •   public class Shipment
        {
            public DateTime shippingdate;
            public object cost { get; set; }
        }
    
        public class Order
        {
            public Shipment Shipment;
            public bool IsShipped { get { return Shipment != null; }}
            public DateTime DatePlaced { get; set; }
            public float TotalProce { get; set; }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var orderprocessor = new OrderProcessor(new ShippingCalculator());
                var order = new Order { DatePlaced = DateTime.Now, TotalProce = 100f };
                orderprocessor.Process(order);
                Console.Read();  
            }
        }
    	
        public class OrderProcessor
        {
            private readonly IShippingCalculator _shippingCalculator;
    
            public OrderProcessor(IShippingCalculator calculator)
            {
                _shippingCalculator = calculator;
            }
    
            public void Process(Order order)
            {
                if (order.IsShipped)
                {
                    throw new InvalidOperationException("The order already is shipped");
                }
    
                order.Shipment = new Shipment
                {
                    cost = _shippingCalculator.CalculateShipping(order),
                    shippingdate = DateTime.Now.AddDays(1)
                };
            }
        }
    	
        public interface IShippingCalculator
        {
            float CalculateShipping(Order order);
        }
    	
        public class ShippingCalculator : IShippingCalculator
        {
            public float CalculateShipping(Order order)
            {
                if (order.TotalProce > 30f)
                {
                    return order.TotalProce * 0.01f;
                }
                return 0;
            }
        }
Interfaces and Extensibility
  • We can use interfaces to change our application’s behaviour by “extending” its code(rather than changing the existing code).
  • If a class is dependent on an interface, we can supply a different implementation of that interface at runtime. This way, the behaviour of the application changes without any impact on that class.
  • For example, let’s assume our DbMigrator class is dependent on an ILoggerinterface. At runtime, we can supply a ConsoleLogger to log the messages on the console. Later, we may decide to log the messages in a file (or a database). We can simply create a new class that implements the ILogger interface and inject it into DbMigrator.
  • 
        public interface ILogger
        {
            void LogInfo(string message);
            void LogError(string message);
        }
        
    	public class DBMigrator
        {
            private readonly ILogger _logger;
    
            public DBMigrator(ILogger logger)
            {
                _logger = logger;
            }
    
            public void Migrate()
            {
                _logger.LogError("DBMigrating started at " + DateTime.Now);
                _logger.LogInfo("DBMigrating ended at " + DateTime.Now);
            }
        }
    
        public class ConsoleLogger : ILogger
        {
            public void LogError(string message)
            {
                Console.WriteLine(message);
            }
    
            public void LogInfo(string message)
            {
                Console.WriteLine(message);
            }
        }
    
    
        public class FileLogger : ILogger
        {
            public void LogError(string message)
            {
                //Here should write the code to insert the log error in to file
                Console.WriteLine(message);
            }
    
            public void LogInfo(string message)
            {
                //Here should write the code to insert the loginfo in to file
                Console.WriteLine(message);
            }
        }
    	
    
References : Udemy.com

No comments:

Post a Comment