Understanding Interfaces via Loose Coupling and Tight Coupling

Tight Coupling is when in a group, classes are highly dependent on one another.

This scenario arises when a class assumes too many responsibilities, or when one concern is spread over many classes rather than having its own class.

Loose Coupling is achieved by means of a design that promotes single-responsibility and separation of concerns.

A loosely-coupled class can be consumed and tested independently of other (concrete) classes.

Interfaces are powerful tools used for decoupling. Classes can communicate,  through interfaces, to other concrete classes, and any class can be on the other end of that communication simply by implementing the interface.

Tight Coupling

public class CustomerRepository {  
    private readonly Database database;  
    public CustomerRepository(Database database) {  
        this.database = database;  
    }  
    public void Add(string CustomerName) {  
        database.AddRow("Customer", CustomerName);  
    }  
}  
public class Database {  
    public void AddRow(string Table, string Value) {}  
} 

Loose Coupling

public class CustomerRepository {  
    private readonly IDatabase database;  
    public CustomerRepository(IDatabase database) {  
        this.database = database;  
    }  
    public void Add(string CustomerName) {  
        database.AddRow("Customer", CustomerName);  
    }  
}  
public interface IDatabase {  
    void AddRow(string Table, string Value);  
}  
public class SqlDatabase: IDatabase {  
    public void AddRow(string Table, string Value) {  
        //Logic to add new customer in sql table  
    }  
}  
public class XMLDatabase: IDatabase {  
    public void AddRow(string Table, string Value) {  
        //Logic to add new customer in XML Document  
    }  
}  

nguồn: https://www.c-sharpcorner.com

Interface Pattern

An interface defines the signature operations of an entity, it also sets the communication boundary between two entities, in this case two pieces of software. It generally refers to an abstraction that an asset provides of itself to the outside.

The main idea of an interface is to separate functions from implementations. Any request that matches the signature or interface of an object may also be sent to that object, regardless of its implementation.

Since it does not matter which implementation of a specific class is used, a class can be exchanged easily without changing the code of the calling class.

The concept of an interface is fundamental in most object oriented programming languages. In some, objects are known only through their interfaces so there is no way to access an object without going through it’s interface.

Applicability / Uses

Use an interface when:

  • you want to specify how classes exchange messages. I.e., every time, when a class should be reused, or used outside a specific context (package) declare the communication interface as an Interface type
  • you have to switch the implementation of a module during run-time
  • at design-time you don’t yet know which implementation you will use at compile-time

Related Patterns

  • Many other patterns use interfaces, a lot of them depend on the interface pattern.
  • It is possible to combine the interface pattern with virtually any other pattern to make them more flexible.

Structure

UML class diagram of the example shown below.

Sample

This example uses an interface for sending messages across the system. The interface defines a single method to send a message:

public interface Messenger {

    public void sendMessage(String receiver, String text);

}

Now someone has to send a Message:

public class Sender {

    public static void main(String args[]) {

        // Retrieve an Implementation of the interface
        Messenger m = getMessenger();

        // Send a message
        m.sendMessage("Bob", "Hello Bob, this is Alice!");
    }

}

Now at last, we need at least on implementation:

public class MailMessenger implements Messenger {

    public void sendMessage(String receiver, String text) {
        
        // Connect to mailserver
        ...
        
        // Send message
        ...
        setReceiver(receiver);
        setBody(text);
        commit();
        ...

        // Disconnect
        ...
    }

}

Notice, that in the Sender-class we didn’t know how the message will be sent. In this case it was sent via mail, but it could also just be printed to stdout:

public class StdOutMessenger implements Messenger {

    public void sendMessage(String receiver, String text) {

        // Just print to stdout
        System.out.println("A message is sent to " + receiver + ":");
        System.out.println(text);
    }

}

Such a construction of using an interface is often combined with the Factory-Pattern to retrieve the Implementation of the interface.

source: http://best-practice-software-engineering.ifs.tuwien.ac.at/patterns/interface.html