2

I am trying to refactor below code to adhere open close principle

Its some bit of code extracted for question purpose but basically here calculate method behave differently based on invoice type

    public class Invoice
        {
            private string _type;
            public double Calculate(double amount)
            {
                if(_type == "invoice")
                {
                    return amount + 10;
                }
                else
                {
                    return amount - 10;
                }
            }
        }

I have done it up to here

public interface IInvoice
    {
        double Calculate(double amount);
    }

    public class Invoice : IInvoice
    {

        public double Calculate(double amount)
        {
            return amount + 10;
        }
    }

    public class DiscountInvoice : IInvoice
    {
        public double Calculate(double amount)
        {
            return amount - 10;
        }
    }

I get below model from a API endpoint, where "Type" determine weather to use Invoice or DiscountInvoice. I like to avoid putting if condition on type field

 public class InvoiceModel
        {
            public int Id { get; set; }
            public string Type { get; set; }
            public double Amount { get; set; }
        }

 static void Main(string[] args)
   {
            private IInvoice _invoice;
        //I am not sure how to detect and use the correct invoice type here. without doing below
        //based on something i have to assign
        _invoice = new Invoice() or new DiscountInvoice()
    } 
user12073359
  • 289
  • 1
  • 11

1 Answers1

1

First of all your structure looks good and meets the open-closed principle.

In terms of determination which implementation of the abstraction to use, you need to consider the business logic, as the decision directly depends on that. If you have several implementations of IInvoice, then I assume you need all of them at some point in your application. So based on your business logic you have to decide which one to use. You can consider Factory pattern, that will take care of that and return you the right type. All the business logic will be encapsulated there. Just when implementing your factory, also keep in mind the LSP (Liskov Substitution Principle), as it's quite easy to break it.

David Oganov
  • 976
  • 1
  • 11
  • 23