The original code in the book is in java.
I chose this book because it has a really unique way of describing things and making them easy to understand maybe somebody else will find it useful.
First you have to generate the auto loader with composer
note: do this step for each file that have composer.json
All examples are tested with php7.2
$ composer dump-autoload
-
chapter 3 : Decorator Pattern (Design Eye for The Inheritance Guy)
-
chapter 4 : Factory method , Abstract factory , Dependency Inversion
-
chapter 8 : Template Method Pattern [Encapsulating Algorithms]
-
chapter 9 : The Iterator and Composite Patterns Well-Managed Collection
aka Policy Pattern
Defines a set of encapsulated algorithms that can be swapped to carry out a specific behavior.
Strategy pattern is used when we have multiple algorithms for specific task and the client decides the actual implementation to be used at runtime.
-
encapsulate what change and you will have flexible system.
-
separate the code that will be changed.
-
Program to an interface not an implementation : an interface in this context could also refers to an abstract class or class that implements particular behavior
-
Represent the behavior of things and not the thing.
-
Think of behaviors as a set of algorithms.
-
Composition over inheritance.
-
ShoppingCart example is not from the book
aka Pub/Sub
According to GoF, observer design pattern intent is;
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
State changes in one or more objects should trigger behavior in other object one-to-many relationship between objects so that when one object changes state all it's dependents are notified and updated automatically.
PHP provides Stander PHP Library (SPL) Observer Pattern through SplObserver interface and SplSubject interface
Model-View-Controller (MVC) frameworks also use Observer pattern where Model is the Subject and Views are observers that can register to get notified of any change to the model.
-
best usage when there's single source of truth one object with many unknown dependents
-
This single source of truth is an Object's state that's many objects care of knowing it.
-
defines one-to-many relationship between objects.
-
the Publisher aka the Subject updates the observer using common interface.
-
the Subscribers aka the Observers are loosely coupled and the subject no nothing about then except that they are implement the observer interface.
-
STRIVE FOR LOOSELY COUPLE DESIGN BETWEEN OBJECT THAT INTERACT.
Allows for the dynamic wrapping of objects in order to modify their existing responsibilities and behaviors.
Attach additional responsibilities to an object dynamically. Provide a flexible alternative to sub-classing for existing functionality.
Decorator pattern is best used when we introduced to existing code that we want to extend its functionality.
since decorators are basically wrappers around objects the PHP I/O classes same as Java uses decorator pattern to add more functionality to the stream to read more Wrappers in php and you can even register a custom wrapper (decorators) to add your own filter/wrapper to I/O stream see this example.
-
Decorator reduce the chance of bugs and side effects in legacy code .
-
Decorator it gives the object new responsibility dynamically at runtime using composition .
-
It follows the open-close principle .
-
General speaking design patterns add abstraction level that's add complexity to code that's way we should always use it on the parts that change and overusing it .
-
In other words ALWAYS IDENTIFY WHAT CHANGES.
-
Again ALWAYS IDENTIFY WHAT's GOING TO CHANGE.
-
Decorators must have the same super-class as the object they decorate.
-
FAVOR COMPOSITION OVER INHERITANCE .
-
Inheritance makes static behavior but Composition make the behavior dynamic and it can change at runtime .
Factory method , Abstract factory , Dependency Inversion ?
The Factory Method Patter defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
+----------------------+
| PizzaStore |
+----------------------+ <- abstract class defines
| | abstract factory method `createPizza()`
| createPizza() | that lets the sub-class decide for it.
| |
| orderPizza() | <abstract product>
| | +-------+
+-----^--------------^-+ | Pizza |<-------+
| | +-^-----+ |
| | | |
| | | |
| | | |
| | | |
| | | |
+---------+------+ ++-----------------+ +------------------+ |
| NYPizzaStore | |ChicagoPizzaStore | |ChicagoCheesePizza| |
+----------------+ +------------------+ +--------^---------+ |
| createPizza() | | createPizza() | | |
| | | +--<creates>----+ |
+-------------+--+ +------------------+ |
<creator> | <creator> +-------------+ |
+---------------------<creates>---->|NYCheesePizza|---------+
+-------------+
When a client doesn't know what concrete classes it will be required to create at runtime, but just wants to get a class that will do the job.
Depend upon abstractions. Do not depend upon concrete classes.
-
You should Depend upon abstraction Not upon an implementation .
-
High-level components should not depend on low-level components they should both depend on abstractions.
-
Instantiation is an activity that should not be in public and can often lead to coupling problems.
-
new
keyword === an Implementation (not an Interface). -
IDENTIFY WHAT CHANGES.
-
Factories (encapsulate) handle details of object creation.
-
Factory method relays on inheritance and delegates the object creation to subclasses which implements the factory method and create concrete objects.
-
Factory method lets subclasses decide what class instantiate not because it allows rather than it does not know the product .
-
Strive for guidelines
The following guidelines can help you avoid OO designs that violate the Dependency Inversion Principle
:
-
No variable should hold reference for a concrete class.
If you use new you’ll be holding a reference to a concrete class. Use a factory to get around that
-
No class should derive form concrete class.
If you derive from a concrete class, you’re depending on a concrete class. Derive from an abstraction, like an interface or an abstract class
-
No method should override method on base class if so then the base class not really an abstraction.
If you override an implemented method, then your base class wasn’t really an abstraction to start with. Those methods implemented in the base class are meant to be shared by all your subclasses.
Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
it's used to construct objects such that they can be decoupled from the implementing system. The pattern is best utilized when your system has to create multiple families of products or you want to provide a library of products without exposing the implementation details.
- The methods of the abstract factory are often FACTORY METHODS.
-
The job of an Abstract Factory is to define an interface for creating a set of products.
-
Abstract factory and Factory method are both great in terms of decoupling application from specific implementation.
-
Factory method uses Classes (inheritance).
-
Abstract Factory uses Objects (objects composition).
The singleton pattern ensures a class has only one instance and provide global access to it .
for anything (object) that unique.
Singletons are used a lot where you need to provide a registry, or something like a thread pool. Logging is also another popular use of Singletons, providing one single access point to an applications log file.
- Singleton violates the Single Responsibility Principle read more on the downsides check this amazing article by James Sugrue
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
it's used to manage algorithms , relationships and responsibilities between objects.
- When history of requests is needed.
- You need a callback functionality.
- Requests need to handled at variant times or in variant order.
- The invoker should be decoupled from the object handling the invocation.
- Decouples the requester of an action from it's preformer.
- command pattern encapsulate requests as objects .
- The client will never bother about the
how
and thewhat
commands will actually do. - The Bank Transaction example is not from the book
- The command pattern forwards the request to a specific moudle.
aka Wrapper Pattern
The Adapter Pattern converts the interface of a class into another interface the client expects. Adapters lets classes work together that couldn't otherwise because of incompatible interfaces.
When a class that you need to use doesn't meet the requirements of an interface. Exposed to legacy code may encounter an old interface needs to be converted to match new client code Adapters allows programming components to work together that otherwise wouldn't because of mismatched interfaces.
Adapter pattern motivation is that we can reuse existing software if we can modify the interface.
-
Class Adapter uses
inheritance
[multiple inheritance] *not supported in java nor php. can only wrap a class It cannot wrap an interface since by definition it must derive from some base class. -
Object Adapter uses
Object composition
composition and can wrap classes or interfaces, or both. It can do this since it contains, as a private, encapsulated member,the class or interface object instance it wraps.
"Because inheritance exposes a subclass to details of its parent's implementation, it's often said that 'inheritance breaks encapsulation'". (Gang of Four 1995:19)
- DON'T MIX DECORATORS WITH ADAPTERS THEY'RE BOTH WRAPPERS BUT DECORATORS ADD NEW RESPONSIBILITIES WHILE ADAPTERS CONVERT AN INTERFACE.
The Facade Pattern provides a unified interface to a set of interfaces in subsystem. Facade defines a higher-level interface that make the subsystem easier to use.
when you want to simplify a complex system.
-
Facades don't encapsulate .
-
Facade Pattern allows to avoid tight coupling between client and subsystem.
-
Design Principle Principle of Least Knowledge - talk only to your immediate friends.
{Least Knowledge principle} aka Law of Demeter
Least Knowledge principle guidelines :
- take any object.
- from any method on that object we should only instantiate :
- The object itself.
- Objects passed as a parameter to the method.
- Any object the method creates or instantiate.
- Any components of the object by instance variable has-A-relationship.
- NOT TO CALL METHODS ON OBJECTS THAT WERE RETURNED FROM ANOTHER METHODS!.
$Q = "What’s the harm in calling the method of an object we get back from another call?"
$A = "if we were to do that, then we’d be making a request
of another object’s subpart (and increasing the number of objects
we directly know). In such cases, the principle forces us to ask
the object to make the request for us; that way we don’t have
to know about its component objects
(and we keep our circle of friends small)."
Without the principle
public function getTemp() : float {
$thermometer = $this->station->getThermometer();
//we get thermometer OBJECT for
//the station then we call get temperature
return $thermometer->getTemperature();
}
With Least Knowledge principle
public function getTemp() : float {
//we add a method to the station class with
//that we reduce the number of classes we're dependent on
return $this->station->getTemperature();
}
PATTERN | INTENT |
---|---|
Decorator | Doesn't alter the interface but adds responsibilities. |
Adapter | converts one interface to another. |
Facade | Makes an interface simpler. |
aka Hollywood pattern
The Template Method Pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
It's all about creating Template
form an Algorithm
$q = "What's a `Template` ?"
$a = "it's just a method that defines an algorithm as steps"
A Hook is a method that declared in the abstract class but given an empty on default implementation ; giving the subclass the ability to hook into
override the algorithm on various points.
When to use what ?
abstract methods
VShooks.
use abstract methods when the implementation is a MUST in the subclass.
for the hooks it's optional for the subclass.
Don't call us, we'll call you.
-
Hollywood principle helps prevents
Dependency rot
. huh ..what!? -
Dependency rot: it's bad and a mess ! it's when high-level components depending on low-level components depending on high-level components ...and so on. it's hard to understand system with such a flaw.
-
Hollywood principle : is a
Technique
for building frameworks or components so that low-level components can beHooked
into the computation without creating dependency between the low-level components and high-level components. -
Hollywood principle guides us to put
decision-making
in high-level modules that can decide how and when to call low level modules. -
The Factory Method is a specialization of Template Method
Pattern | Description |
---|---|
Template Method | Subclasses decide how to implement steps in an algorithm. |
Strategy | Encapsulate interchangeable behavior and use delegation to decide which behavior to use. |
Factory Method | Subclasses decide which concrete classes to create. |
another great example from journaldev
to understand the method template pattern
suppose we want to provide an algorithm to build a house. The steps need to be performed to build a house are – building foundation, building pillars, building walls and windows. The important point is that the we can’t change the order of execution because we can’t build windows before building the foundation. So in this case we can create a template method that will use different methods to build the house.
- Template Methods are frequently used in general purpose frameworks or libraries that will be used by other developer.
- When the behavior of an algorithm can vary but not the order.
- When there's a code duplication this is always gives a clear sign of bad design decisions and there's always room for improvement.
The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
- Iterator provide a standard way common interface to traverse through a group of Objects aggregate.
- Iterator allows access to an aggregate's elements without exposing its internal structure.
$ git checkout iteratorPattern
Switched to branch 'iteratorPattern'
- The Aggregate defines an interface for the creation of the Iterator object.
- The ConcreteAggregate implements this interface, and returns an instance of the ConcreteIterator.
- The Iterator defines the interface for access and traversal of the elements, and the ConcreteIterator implements this interface while keeping track of the current position in the traversal of the Aggregate.
- When you need access to elements in a set without access to the entire representation.
- When you need a uniform traversal interface, and multiple traversals may happen across elements.
Unlike java , PHP Array can be treated as an array, list, hash-table, stack, queue, dictionary, collection,...and probably more.
The original example uses both Java Array and ArrayList.
For the sake of Objectville
example :
- I will use SplFixedArray to mimic (static)fixed size arrays.
- We will ignore the fact that both normal php
array
andSplFixedArray
implement the Traversable interface and that both can be easily traversed using aforeach
. - You cannot implement
Traversable
interface it's an abstract base interface, you can't implement it alone but you can implement interfaces calledIterator
orIteratorAggregate
By implementing either of these interfaces you make a classiterable
andtraversable
usingforeach
- For the sake of this example we're going to make our own interface and we call it
IteratorInterface
.
A Class should have only one reason to change.
Separating responsibilities in design is one of the most difficult things to do, to succeed is to be diligent in examining your designs and watchout for signals that a class is changing in more than one way as your system grows.
We should strive to assign only one responsibility to each class.
The Composite Pattern allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
The << Component >> abstract class define all objects in composed system.
The Leaf has no children.
The Composite contains components.
-
Composite pattern comes into play when developing a system where a component could either be an individual object or a representation of a collection of objects.
-
Composite pattern provides a structure to hold both individual objects an composites.
-
A Component is any object in a Composite structure.
-
Components may be other composites or leaf nodes.
-
Remember to balance
transparency
andsafety
.
The Composite Pattern
-
manages a hierarchy
-
performs operations related to Menus
that's 2 responsibilities.
The Composite Pattern trades Single Responsibility Principle for transparency
Transparency: Since the Composite interface contain child management operations and the leaf (items non iterable) operations The client can treat both the composites and leaf nodes uniformly, both are transparent to the client.
Having both operations in the Component class will cause a bit loss of safety because the client might try to do Composite related operation e.g add to a leaf item which is invalid.
- Graphics frameworks are the most common use of this pattern.
- The Composite pattern is frequently used for abstract syntax tree representations.
- when dealing with tree structures Anything that can be modelled as a tree structure can be considered an example of Composite.
- when you have collection of objects with whole-part relationships and you want to be able to treat those objects uniformly.
also known as aggregation relationship
it's a relationship between two classes in which one represent the larger class (whole) that consists of smaller classes (parts)
-
We call components that contain other components
composite objects
and components that don't contain other componentsleaf objects
. -
By treating objects uniformly that means there's a common methods can be called on both
composite
orleaf
that implies that both must have the sameinterface
.
Pattern | Description |
---|---|
Strategy | Encapsulate interchangeable behavior and use delegation to decide which behavior to use. |
Adapter | Changes the interface of one or more classes. |
Iterator | Provides a way to traverse a collection of objects without exposing the collection's implementation. |
Facade | Simplifies the interface of a group of classes. |
Composite | Clients treat collections of objects and individual objects uniformly. |
Observer | Allow a group of objects to be notified when some state changes. |
Allows an object to alter its behaviour when its internal state changes. The object will appear to change its class.
- The Context have number of internal states.
- The State << interface >> defines a common interface for all concrete states.
- Each Behavior correspond with ConcreteState implements its own logic for the request.
- When Context changes state a different ConcreteState associate with it.
- Simply change the state object in context to change the behavior.
This is similar to Strategy Pattern except changes happens internally rather than the client deciding the strategy.
key-points: Think of Strategy Pattern as a flexible alternative to sub-classing. Think of State Pattern as an alternative to putting lots of conditionals.
- You need a class to behave differently based on some condition.
- If you are using if-else condition block to perform different actions based on the state.
Pattern | Description |
---|---|
State | Encapsulate state-based behavior and delegate behavior to the current state. |
Strategy | Encapsulate interchangeable behavior and use delegation to decide which behavior to use. |
Template Method | Subclasses decide how to implement steps in an algorithm. |