Search code examples
design-patternsinterfaceimmutabilityreadonlyfacade

What is the difference between the read-only interface pattern and the facade pattern?


Say I write a facade for a class and expose all it's methods except for it's setters. What is the functional difference with the read-only interface pattern?

Based on the wikipedia article on immutable interfaces I'd say the facade has the advantages of the immutable interface (when I name my class Foo and my facade is ImmutableFoo) while not having the disadvantage of being able to cast the immutable interface "to their concrete, mutable type, and have their state mutated".

EDIT

As it turns out the immutable interface article on Wikipedia doesn't talk about the read-only interface pattern, which is described on slide 49 and 50 in this presentation. The answer is that both facade and the read-only interface can indeed be achieved by using a wrapper class, however they serve different purposes (see the accepted answer and comments for a more detailed observation).


Solution

  • The main purpose of Facade pattern is not to make your interfaces immutable.

    From Wikipedia:

    A facade is an object that provides a simplified interface to a larger body of code, such as a class library. A facade can:

    • make a software library easier to use, understand and test, since the facade has convenient methods for common tasks;
    • make the library more readable, for the same reason;
    • reduce dependencies of outside code on the inner workings of a library, since most code uses the facade, thus allowing more flexibility in developing the system;
    • wrap a poorly designed collection of APIs with a single well-designed API (as per task needs).

    Facades can be mutable. They are used to provide a simplified interface.

    Before you call a class a 'Facade', you should ask yourself, does it provides a simplified interface and make the library easier to use?

    They might have some overlap, but the main purposes are different.

    Facade Is About API Simplification

    Say you are developing an order processing feature for an Ecommerce system. Your core library provides three methods: ChangeOrderStatus(), SendOrderToFulfillment(), SendOrderUpdateEmailToCustomer().

    Without a facade, you have to call all these three methods wherever you need to approve an order. It's so boring and easy to make mistakes. If you add an ApproveOrder() method as a Facade (which simply calls that three method), you will only need to call ApproveOrder() wherever you need to approve an order. This simplify the api, and make the library easier to use.

    If your application is clearly split into multiple layers. You might have a very thin Facade Layer on top of your infrastructure layer. All your UI code will interact with the facade layer instead of the infrastructure layer. In my example, ApproveOrder() is in the facade layer, while ChangeOrderStatus(), SendOrderToFulfillment(), SendOrderUpdateEmailToCustomer are in the infrastructure layer.

    Read-only Interface Is About Data Protection

    Some objects are supposed to be immutable. For example, immutable objects are often preferred in multi-threading, because they don't expose methods to change their states, so they are safe to be shared among threads.

    Pattern vs. Goal

    From the slide (page 50) you mentioned, the "Read-only Interface" pattern is a specific pattern to achieve "immutable". But it's not the only way to achieve "immutable".

    If you follow the specific "Read-only Interface" pattern, we can say you implement the pattern. But if you use some other approach to achieve "immutable", we can't say you implement the "Read-only Interface" pattern, but you do achieve the "immutable" goal.

    Does it matter if you implement the "Read-only Interface" pattern or not? Of course not, you care about "immutable", not the specific "Read-only Interface" pattern. (Sometimes, the api has setters, but they will throw exceptions if you call them. This is another way to achieve "immutable". You just have to choose the most suitable solution to achieve a same goal.)