[Yugong series] December 2021: object oriented design principles - Interface aggregation principle or ISP

Article catalog

preface

There are seven commonly used object-oriented design principles. These seven design principles are based on maintainability and reusability. These principles do not exist in isolation. They are interdependent and complementary. Following these design principles can effectively improve the reusability and maintainability of the system.

Tip: the following is the main content of this article. The following cases can be used for reference

1, Interface Segregation Principle or ISP

The client should not rely on interfaces that it does not need. The dependence of one class on another should be based on the smallest interface.

2, Use steps

Example

public abstract class InvoiceBase {

    string InvoiceCode { get; set; }
    string InvoiceNumber { get; set; }

}
public interface IInvoice {

    bool CreateInvoice(InvoiceBase invoice);
    bool PrintInvoice(InvoiceBase invoice);
    bool SendInvoice(InvoiceBase invoice);

}
public class Invoice : InvoiceBase, IInvoice {

    public bool CreateInvoice(Invoice invoice) {
        Console.WriteLine("Create Invoice!");
        return true;
    }

    public bool PrintInvoice(Invoice invoice) {
        Console.WriteLine("Print Invoice!");
        return true;
    }

    public bool SendInvoice(Invoice invoice) {
        Console.WriteLine("Send Invoice by Email!");
        return true;
    }

}

Firstly, an invoice base class is established with InvoiceBase, which contains two public attributes: Invoice Code and invoice number. IInvoice interface includes three "actions" including generating invoice, printing invoice and sending invoice. It is reasonable that generating and printing invoices belong to the IInvoice interface, and then sending invoices is not the same in this interface, because we don't want to send some invoices. The result of this design is that the implementation class invoice will eventually become bloated, because the IInvoice interface is too "fat". Another consequence of this design is that it is not conducive to future expansion. For example, we want to add an invoice voiding action for invoices. We have to modify all IInvoice implementation classes, but these modifications are not necessary. In some implementation classes, we just want to use the invoice sending action, but we have to add an implementation code for invoice cancellation, which obviously violates the opening and closing principle. Here is a solution for reference:

public interface IInvoiceAction {

    bool CreateInvoice(IInvoiceBase invoice);
    bool PrintInvoice(IInvoiceBase invoice);
    bool CancelInvoice(IInvoiceBase invoice);

}
public interface IInvoiceNotify {

    bool SendInvoice(IInvoiceBase invoice);

}

Establish IInvoiceAction interface and iinvoicinotify interface to separate invoice behavior and invoice sending action.

public interface IInvoice : IInvoiceAction, IInvoiceNotify {

}

Establishing the joint interface IInvoice is convenient. In some cases, it is necessary to use both functions at the same time.

//VAT invoice
public class VatInvoice : InvoiceBase, IInvoiceAction {

    public string CheckCode { get; set; }

    public bool CreateInvoice(IInvoiceBase invoice) {
        Console.WriteLine("Create Invoice!");
        return true;
    }

    public bool PrintInvoice(IInvoiceBase invoice) {
        Console.WriteLine("Print Invoice!");
        return true;
    }

    public bool CancelInvoice(IInvoiceBase invoice) {
        Console.WriteLine("Cancel Invoice!");
        return true;
    }

}
//Electronic invoice
public class ElectronicInvoice : InvoiceBase, IInvoiceNotify {

    public string PdfFile { get; set; }

    public bool SendInvoice(IInvoiceBase invoice) {
        Console.WriteLine("Send Invoice by Email!");
        return true;
    }

}

VAT invoice class VatInvoice and electronic invoice class ElectronicInvoice only implement IInvoiceAction or iinvoicinotify interfaces, and add check code and Pdf file attributes.

In this example, we assume that the electronic invoice does not implement the IInvoiceAction interface. We just want to send the PDF file of the electronic invoice.

public class Invoice : InvoiceBase, IInvoice {

    public bool CreateInvoice(IInvoiceBase invoice) {
        Console.WriteLine("Create Invoice!");
        return true;
    }

    public bool PrintInvoice(IInvoiceBase invoice) {
        Console.WriteLine("Print Invoice!");
        return true;
    }

    public bool CancelInvoice(IInvoiceBase invoice) {
        Console.WriteLine("Cancel Invoice!");
        return true;
    }

    public bool SendInvoice(IInvoiceBase invoice) {
        Console.WriteLine("Send Invoice by Email!");
        return true;
    }

}

The implementation class of joint interface IInvoice is Invoice, which is convenient for using all functions at the same time in some cases.

summary

Through the above code transformation, we minimize the interface functions. Each interface is only responsible for its own related functions to prevent "interface pollution" caused by too many functions, which conforms to the interface isolation principle, is conducive to future expansion, and conforms to the opening and closing principle.

Posted on Fri, 03 Dec 2021 04:02:45 -0500 by veryconscious