Layers Pattern

Most of the services that a layer provides are composed of services provided by layer J -1. In other words, the services of each layer implement a strategy for combining the services of the layer below. In addition, a layer's services may depend on other services in the same layer. The main structural characteristic of the Layers pattern is that the services of Layer J are only used by Layer J + 1 and there are no further direct dependencies between layers. This structure can be compared with a stack.

Example: TCP/IP stack.

If Layer J should be a 'black box' for Layer J+1, design a flat interface that offers all Layer J's services, and perhaps encapsulate this interface in a Facade object.

Bottom-up communication:
You can use callbacks and still preserve a top-down one-way coupling. Here the upper layer registers callback functions with the lower layer. This is especially effective when only a fixed set of possible events is sent from lower to higher layers. During start-up the higher layer tells the lower layer what functions to call when specific events occur. The lower layer maintains the mapping from events to callback functions in a registry.

Exception Handling:
As a rule of thumb, try to handle errors at the lowest layer possible. This prevents higher layers from being swamped with many different errors and voluminous error-handling code. As a minimum, try to condense similar error types into more general error types, and only propagate these more general errors. If you do not do this, higher layers can be confronted with error messages that apply to lower-level abstractions that the higher layer does not understand.

Variants/Consequences:

Layering Through Inheritance:
Is a variant to the main pattern; In this variant a higher layer requesting services from a lower layer inherits from the lower layer's implementation and hence can issue requests to the base class services. An advantage of this scheme is that higher layers can modify lower-layer services according to their needs. A drawback is that such an inheritance relationship closely ties the higher layer to the lower layer.

Exchangeability:
Individual layer implementations can be replaced by semantically-equivalent implementations without too great an effort. You can even replace an old implementation with an implementation with a different interface by using the Adapter pattern for interface adaptation. The other extreme is dynamic exchange, which you can achieve by using the Bridge pattern.

Unnecessary work:
If some services performed by lower layers perform excessive or duplicate work not actually required by the higher layer, this has a negative impact on performance. An example is error correction in file transfer. A general purpose low-level transmission system can be written first and provides a very high degree of reliability, but it can be more economical or even mandatory to build reliability into higher layers, for example by using checksums.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License