Design patterns and principles - A high-level view

Design patterns and principles - A high-level view

It's not a rule of thumb that you have to use design patterns at all costs. They are just there to guide you in solving a problem systematically, using well-tested approaches that have stood the test of time. What you need to do is to familiarize yourself with what pattern becomes applicable in what situation.

Design patterns will guide you into producing elegant and robust code, but that does not mean that there are no alternative ways to solve a problem.

In most cases, when you analyze any problem you are trying to code for, there will be several pathways you could take, and you are well justified to take any other path that you feel will make the most sense to you. But it's always safer when you see an applicable design pattern fitting in the solution to go that way.

With design patterns, you are assured of good maintainability since other developers will be able to understand your approach to solving a problem much faster than your path. In addition, using design patterns guarantees stability because these patterns have matured over time.

Gang of four?design patterns

Some of the widely popular approaches to software development?originated from influential software developers?and authors, whom I have alluded to in a previous article on software architecture. Similarly, there is also what is called the Gang of four design patterns, which came from a book called ' Design Patterns: Elements of Reusable Object-Oriented Software '.

This book was first published in 1994 by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. It was nicknamed 'Gang of Four' design patterns?because of the four authors. Hence up until now, they are referred to as "GoF Design Patterns".

The GoF Design Patterns?divides into three categories, namely creational, structural, and behavioral design patterns, and I'll introduce them below.

Note: Again, reminding the reader that these article series remain to be a ‘guide’, and code explanations are out of scope, which could make it easier for some readers to grasp the short form definitions presented in this section. I won’t go deep into details, as this topic can make a book of its own, but as a reader, you are expected to dig a bit deeper into each pattern independently.?

Creational design patterns

This design pattern deals with the creation of an object in the run time for an application. Five design patterns classify as creational. I'll briefly define them as follows, in alphabetical order:?

  • Abstract factory pattern:- this aims at creating groups of related objects. The interface of an Abstract Factory typically contains several Factory Methods, one for each type of object to be made.
  • Builder pattern:- this entails creating an object step-by-step and further contains a method to get the object instance finally.
  • Factory pattern:- this takes out the responsibility of instantiating an object from a class?to a factory class.
  • Prototype pattern:- this involves creating a new object instance from another similar model and then modifying it according to requirements.
  • Singleton pattern:- this restricts the initialization of a class?to ensure that a program creates only one class instance.

Structural design patterns

This design pattern type deals with the structure of a class, an example of which is inheritance?and composition. Seven design patterns classify as structural in their nature.

  • Adapter pattern:- this provides an interface between two unrelated entities so that they can work together.
  • Bridge pattern:- this is used to decouple interfaces from implementation and hide implementation details from a client program.
  • Composite pattern:- this is used when we have to implement a part-whole hierarchy. For example, imagine a diagram that is made out of different other pieces, such as circles, squares, and triangles, all composing the main diagram.
  • Decorator pattern:- this is used to modify the functionality of an object at runtime.
  • Facade pattern:- this involves creating a wrapper interface on top of existing interfaces to help client applications.
  • Flyweight pattern:- this entails caching (keeping) objects in RAM?and reusing the object instances.
  • Proxy pattern:- this provides a surrogate or placeholder for another object to control access to it.

Behavioral design patterns

This type of design pattern?provides solutions for better interaction between objects, providing loose coupling and flexibility to extend easily in the future. Eleven design patterns are described as behavioral in nature, and I'll briefly define them below:

  • Chain of Responsibility pattern:- this is used to achieve loose coupling in software design where a request from a client is passed to a chain of objects to process them. Upon receiving a request, each object decides whether to process the request or pass it to the next object in the chain.
  • Command pattern:- this is used to turn a request, in a request-response model, into a stand-alone object containing all the requested information. This transformation lets you pass requests as method arguments and delay or queue the request's execution.
  • Interpreter pattern: - this defines a grammatical representation of a language and provides an interpreter to deal with this grammar.
  • Iterator pattern:- this is used to provide a standard way to traverse a group of objects.
  • Mediator pattern:- is used to provide a centralized communication medium between different objects in a system.
  • Memento pattern:- this is used when we want to save the state of an object so that we can restore it later on.
  • Observer pattern:- this is useful when you are interested in the state of an object and want to get notified whenever there is any change.
  • State pattern:- this is used when an object changes its behavior based on its internal state.
  • Strategy pattern:- this is used when we have multiple algorithms for a specific task and the client decides the actual implementation to be used at runtime.
  • Template Method pattern:- is used to create a template method stub and defer some of the implementation steps to the subclasses.
  • Visitor pattern:- this is used when we have to operate on a group of similar kinds of objects. Visitor pattern allows you to separate algorithms from the entities on which they operate.

Design Principles

SOLID principles

Like design patterns, these are just guiding principles in writing software that is elegant and will stand the test of time. Software development is ideally teamwork, and even if you work on an application alone, that application will probably outlive your availability. Maintenance by other people should always be a priority to be considered. It's no use writing code that only you understand.

Code that does not follow these guiding principles will still work, but an excellent object-oriented software developer is often noted for how they keep to these principles when writing their code. These are named SOLID principles, as just an acronym that is put together from the first letters of the principles: Single responsibility principle, Open but closed principle, Liskov substitution principle, Interface segregation principle, Dependency inversion principle.?I'll briefly define these principles below:

  • The single responsibility principle?- proposes that a class?should have only one responsibility. So, for example, if you have a 'Person' class, it should only worry about the domain problem regarding the person itself and not its persistence in the database.

For that, you may want to use a PersonDAO, for example.

If a class?uses too many external dependencies (that is, other classes), that's a symptom that the class has too many responsibilities.

●?????Open-Closed principle?proposes that classes should be extensible but not modifiable. So, for example, adding a new field to a class?is okay, but changing existing things is not.

In the bigger picture, other components of the program may depend on the field you are changing.

●?????Liskov substitution principle?- this proposes that a class?that expects an object of type 'Animal', for example,?should work if a subclass 'Dog' and a subclass 'Cat' are passed.

For example, class?'Animal' should NOT have a method called bark since subclasses of type 'Cat' won't be able to bark.

Classes that use the 'Animal' class also shouldn't depend on methods?that belong to a class 'Dog'.

●?????Interface segregation principle?- this proposes keeping your interfaces as small as possible. So, for example, a class?'Teacher' that is a student should implement both 'IStudent' and 'ITeacher' interfaces instead of a single big interface called 'IStudentAndTeacher'.

●?????Dependency inversion principle?- Proposes that objects should not instantiate their dependencies but receive them instead.

For example, a class?'Car' that has an 'Engine' object inside should not do

engine = new PetrolEngine();        

Instead, a program should pass the said engine to the class 'Car' through the constructor. This way, the car class will not be coupled to the PetrolEngine class.

Now that we have looked at language agnostic concepts, this is a perfect moment to start thinking about programming languages, which I will introduce in the following article. First, notice the steps you have gone through before to get to this point.

If you came straight to programming languages?to learn a language, you could have missed the bigger picture. Unfortunately, many programming instructors miss these steps and make their audience start coding too early. When an instructor introduces the concepts mentioned earlier, it's much harder to conceptualize or place them. We'll briefly look at programming languages in the following?article.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了