Table of Contents
Design Patterns in PHP
The article is an overview of design patterns in PHP, their importance, types, history, and criticism. Here are some quick bits from the article.
- A design pattern is a generic solution to recurring design problems.
- A good design’s top features are scalability, maintainability, and efficiency.
- A software system may perform the intended functionality correctly regardless of the design.
- Good design promotes scalability, flexibility, and maintainability.
- Three types of design patterns are Creational, Structural, and Behavioral.
- The Gang of Four (GoF) introduced design patterns in their book.
These are some quick facts, but we recommend you read the full article to understand thoroughly.
What is a Design Pattern?
Computer programming is more than just learning syntax.
A considerable focus of computer programming is on problem-solving. Languages, frameworks, libraries, and other tools are there to help solve problems.
Though the problem statements can vary, there is usually a recurring pattern in many problems that seem apparently distinct. For instance – all the nested data structures may have recursive patterns. If you are efficient in applying recursion, you may be able to tackle virtually any problem involving such data structures.
That’s one effective way of problem-solving – identifying recurring patterns. That’s what the idea of design patterns is all about.
“A design pattern is a generic solution to recurring design problems.”
Design patterns are not algorithms.
Patterns are neither algorithms nor computer programs. They are not hard and fast programming rules either. You may not apply a design pattern, and your program will still run. Running a computer program is one thing and designing an efficient and scalable solution is another.
Design patterns are derived by experienced individuals who have been through design problems frequently occurring when designing an object-oriented software program. So, these patterns are a sort of observation and experience, general templates, and design decisions you can reuse in the right scenarios to develop better software systems.
But what is a good design in software development?
A well-designed software has some prime characteristics that set it apart from the bad ones. A good design’s top features are scalability, maintainability, and efficiency. Though there are other essential features that software must accomplish but from a design POV, these are the top three players.
Design patterns are a means to an end, meaning that they help us design scalable, efficient, and maintainable systems. Some fundamental ideas of modularity, decoupling, and interface programming are vital to good design. Thus, the patterns rely on these fundamentals and help us identify the right scenarios to engineer better solutions.
Good Design vs. Bad Design
Enough theory. Let’s look at a program that relies on a third-party Email service to send Emails. The visual below compare two software designs. Both of these accomplish the Email functionality. So, what’s the catch, then? Can you figure it out?
Well, the components are rightly connected. A client program calls an Email service and delegates email-sending functionality to it. That’s correct, isn’t it? But think for a while about what happens if.
- You need to switch to a new email service.
- You need to use more than one service and switch dynamically.
These are some changes that are highly likely to happen. A new Email service could be drastically different than the one you are using. Now, if your client program is tightly bound to the Email service implementation, you must make many changes in the client code.
It is not unusual to break things and introduce bugs while trying to make changes. This issue is escalated if someone else has developed it, and now you’re stuck with all the problems and bugs. The problem can be huge if many other components rely on the Email service. This design is undoubtedly a maintenance nightmare.
Besides, this design violates the Open-closed principle, which is one of the fundamental design principles and states that
‘A software should be open for extension but closed for modification.’
So, how to improve this design and build more scalable software?
So what’s up with the ‘<interface> SendEmail’? What difference does it make? Think of it as an abstraction. The client or any other code that needs Email functionality would call the interface function without worrying about the underlying Email services.
What’s the benefit of this abstraction? Other modules are not tightly coupled with the underlying Email service. The software is flexible, extendable, and maintainable. Need to change the Email service? Implement this interface in the new service, and the rest of the code will work fine. You don’t need to make any changes to the existing code.
Need to add more than one Email service? Implement this interface in other services, and you can dynamically switch them during runtime. Long short story, your modules see the interface only, and it doesn’t care about what Email services are and how they have been working.
Contrary to this design, the bad design had tightly coupled modules. The client code was highly dependent on the Email service. Therefore, any change to the Email service had a chain reaction on the rest of the program.
Design Patterns to the Rescue
We have seen a good design and a bad design. A fun fact is that regardless of the design, both programs could accomplish the user functionality of sending emails. The flaws are more apparent in the long run when change requests kick in, and maintenance activities are scheduled. Bad design can be a pain point at that moment.
Developers are often tempted to devise a solution without considering factors that can negatively impact the design and architecture. In software development, change is the only constant. Therefore, if your software is inflexible and resistant to change, it will cost you alot of time, effort, and money.
So, next time ask yourself these questions even if your software passes the functionality check.
Design Patterns in PHP
Design patterns are general templates and observations. They are not bound to a programming language. You can, however, apply them in any programming language of your choice. We will learn how to use design patterns in PHP in future articles. More scenario-oriented design patterns articles will follow this introductory article in PHP.
Why use Design Patterns?
Though much has been clear about the usefulness of design patterns, the following are some essential summary points.
- Improves the software architecture using the tested design paradigms.
- Accelerates the development process by using patterns for recurring problems.
- Improves code readability and standardization.
- Implicitly employs best practices and design principles.
- Helps in knowledge sharing and process documentation.
- It makes the software system more scalable and maintainable.
Types of Design Patterns
Design Patterns are broadly categorized as follows.
- Creational Design Patterns
- Structural Design Patterns
- Behavioral Design Patterns.
Each of them has numerous design patterns. Let’s have a brief overview.
Creational Design Patterns
As the name suggests, Creational design patterns are concerned with class instantiation. We are familiar with the new keyword for creating objects of a class. While this may be an obvious way to instantiate an instance of a class, it is not always the most flexible.
The creational pattern uses object-oriented paradigms to delegate the instantiation.
- Abstract Factory
Uses abstraction to create instances of families of sub-classes.
Calls a method to construct a complex object step-by-step.
- Factory Method
Uses abstraction to create instances of sub-classes.
- Object Pool
Reuses objects from an existing pool.
Clones an existing object.
Creates a single global object.
Structural Design Patterns
Structural design patterns help in composing and building complex relationships between objects and classes to obtain new functionalities.
Adapt one interface to a different kind.
Uses abstraction to separate abstract and concrete classes.
Creates a tree structure to define hierarchies.
Uses decorator classes to add functionalities on the fly.
Uses shared states to use memory efficiently.
Provides a convenience class for complex sub-systems.
Uses an object to represent another.
- Private Class Data
Creates a class to limit data exposure.
Behavioral Design Patterns
Behavioral design patterns are concerned with communication between objects.
Encapsulates commands as objects.
- Chain of responsibility
Regulates the flow of data in a system.
Defines a class for iterating different traversable data structures.
Provides an interpreter class to deal with expressions in the program.
Memorizes a former state of an object for restoration purposes.
Uses a mediating class for simplified object communications.
Uses a change notification mechanism.
Encapsulates algorithms in a concrete class.
Alters an object’s behavior with changing state.
- Template Method
Defines a template of algorithms and functions for sub-classes to implement.
Defines new operations without modifying the existing classes.
History of Design Patterns
Patterns are a common phenomenon in many other fields of life. An architect, Christopher Alexander, first articulated the concept of using patterns in architecting buildings and infrastructure.
This idea became popular in software development because designing or engineering software is similar to designing a physical structure. Many attempts have been made to define various design principles and patterns.
The Gang of Four (GoF)
Erich Gamma, John Vlissides, Ralph Johnson, and Richard Helm are four authors commonly known as the Gang of Four (GoF). In 1994, they published Design Patterns: Elements of Reusable Object-Oriented Software, in which they introduced the design patterns idea in object-oriented software design.
They included around 23 patterns in their book and became popular in the dev circles. The same book by the GoF inspires the patterns we have included in this article.
Criticism of Design Patterns
Blaming the Programming Languages
Some developers think that design patterns are applicable in languages with low abstraction, for instance – C or C++. High-level and modern languages may not need any pattern because it comes with abstractions out of the box. So, most experts believe that it is an inherent problem with programming languages.
Overuse of Patterns
Some developers criticize the design patterns for unnecessarily increasing code complexity. At the same time, this is debatable because patterns are not supposed to be overused. They are best practices and not some hard-and-fast rules. Developers tend to use patterns unnecessarily, which compromises readability and efficiency most of the time.
No Formal Ground
Like any other engineering branch, software development is highly rational and algorithmic. It relies on standardization and a fixed set of rules. So, many people blame the GoF had no formal ground for publishing their work, and they were up for more general guidelines, which were not backed by any research.
What’s Next in Design Patterns in PHP?
We will be coming up with more design pattern articles where we will talk about the design patterns and include some excellent examples, scenarios, and PHP code to help you get the most out of this series.
So stay tuned at FuelingPHP for more!
This introductory article explains design patterns, why they are essential, and what the types are. It also overviews the characteristics of a good design and how it leverages software in terms of scalability and flexibility. Finally, it dives into the historical context and criticism of design patterns.
Get deeper with PHP
We have many fun articles related to PHP. You can explore these to learn more about PHP.