Leaky encapsulation

This bad taste results when abstractions expose or give away implementation details through public interfaces (methods). It’s important to note that even if an abstraction doesn’t have the bad taste of “inadequate encapsulation,” its public interface can give away implementation details.

Why not leak the package?

To achieve effective encapsulation, you must separate the abstract interface (that is, the abstract content) from the implementation (that is, the abstract way). To follow the hiding principle, the implementation aspects of the abstraction must be hidden from the client.

Exposing implementation details through a public interface (in violation of the hiding principle) may result in:

  • When changes are made to the implementation, clients may be affected
  • Exposed implementation details may enable clients to access internal data structures through public interfaces, thereby intentionally or unintentionally corrupting the abstract internal state.

## Potential cause of leakage of encapsulation

I don’t know what to hide

Developers often inadvertently divulge implementation details.

Use fine-grained interfaces

The public interface of a class directly provides fine-grained methods that often expose unnecessary implementation details to the client. It is better to provide coarse-grained methods in the public interface of the class and use fine-grained private methods inside the coarse-grained methods.

Example Analysis 1

We use programs to maintain a to-do list. In the ToDoList class, the public method GetListEntries() returns a list of to-do items stored in the object.

public class ToDoList
{
    private List<string> listEntries = new List<string>();

    public List<string> GetListEntries()
    {
        return listEntries;
    }

    public void AddListEntry(string entry)
    {
        
    }
}
Copy the code

The problem is the method’s return type, which reveals an internal detail that ToDoList uses internally to store to-do lists using lists.

Now here’s the thing. If the to-do List program does mostly insert and delete operations, there’s nothing wrong with using a List. But when it turns out that lookups are more frequent than modifications, using HashTable might be more appropriate. However, the return type of GetListEntries() is List, and changing the return type of this method may break clients that depend on it. To support future changes to the data structure, a method return type can use IEnumerable (the interface type that all collection types in C# implement), which can then replace the data structure that stores the to-do list without changing the method signature (the reefer rule).

The refactored code implementation:

Using the List data structure:

public class ToDoList
{
    private List<string> listEntries = new List<string>();

    public IEnumerable GetListEntries()
    {
        return listEntries;
    }

    public void AddListEntry(string entry)
    {
        
    }
}
Copy the code

Using the Hashtable data structure:

public class ToDoList
{
    private Hashtable listEntries = new Hashtable();

    public IEnumerable GetListEntries()
    {
        return listEntries;
    }

    public void AddListEntry(string entry)
    {
        
    }
}
Copy the code

Another serious problem with the getListEntry () method is that it returns a reference to an internal data structure through which clients can bypass the AddListEntry() method and modify the data structure directly. Of course, this problem can be solved by using IEnumerable, because the IEnumerable interface has no corresponding operations for a single set of data.

Public interface IEnumerable {// // Abstract: // Returns the enumerator for the loop access collection. / / / / return the result: / / a set can be used to iterate through the System. Collections. IEnumerator object. [DispId(-4)] IEnumerator GetEnumerator(); }Copy the code

Example Analysis 2

Assume that an explicit image contains four steps that must be executed in a specific order for the graph to be properly explicit.

The Image class now provides four public methods, Load(),Process(),Validate(), and Show(), for the client to use, but the problem with this is that the developer writing the client doesn’t necessarily call the methods in the correct order (never give the client a choice). And since clients only want explicit images, why should we expose them to four internal steps? This is the underlying cause of leaky encapsulation — the use of fine-grained interfaces.

public class Image
{
    public void Load()
    {
    }
    public void Process()
    {
    }
    public void Validate()
    {
    }
    public void Show() {}}Copy the code

To solve this problem, you can have the Image class expose a single method Display() to the client, and then call the four-step methods within that method in a specific order.

public class Image
{
    private void Load()
    {
    }
    private void Process()
    {
    }
    private void Validate()
    {
    }
    private void Show()
    {
    }

    public void Display() { Load(); Process(); Validate(); Show(); }}Copy the code

conclusion

  1. Can clients directly depend on implementation details when abstractions expose or reveal them through public interfaces, making it difficult to modify or extend the design without breaking existing client code?
  2. The integrity of an abstraction is compromised when it betrays the internal data structure. Increases the likelihood of problems occurring at runtime.

Reference: Software Design Refactoring



                                                    —–END—–



If you like this article, please scan the picture below and watch more exciting content