Design Patterns
Design Patterns
Implementation Considerations
- You can easily create an immutable class by implementing builder as an inner static
class. You’ll find this type of implementation used quite frequently even if
immutability is not a main concern.
this way setter methods can be declared private for the outer class
Design Considerations
- The director role is rarely implemented as separate class, typically the consumer of
the object instance or the client handles that role.
- Abstract builder is also not required if "product" itself is not part of any
inheritance hierarchy. You can directly create concrete builder.
- If you are running into a ”too many constructor arguments” problem then it’s a
good indication that builder pattern may help.
Pitfalls
- A little bit complex for new comers mainly because of 'method chaining’, where
builder methods return builder object itself.
- Possibility of partially initialized object; user code can set only a few or none
of properties using with methods and call build(). If required properties
are missing, build method should provide suitable defaults or throw exception.
-move the instantiation logic to a separate class and most commonly to a static method of this class
-some do not consider it a design patter, as its simply a method that encapsulates object instantiation
-typically we want to do this if we have more than one option when instantiating object and a simple logic is used to
choose the correct class
- Simple factory encapsulates away the object instantiation in a separate method.
- We can pass an argument to this method to indicate product type and/or additional
arguments to help create objects
Factory pattern
Implementation Considerations
- The creator can be a concrete class & provide a default implementation for the
factory method. In such cases you'll create some "default" object in base creator.
- You can also use the simple factory way of accepting additional arguments to choose
between different object types. Subclasses can then override factory method to
selectively create different objects for some criteria.
Design Considerations
- Creator hierarchy in factory method pattern reflects the product hierarchy. We
typically end up with a concrete creator per object type.
- Template method design pattern often makes use of factory methods.
- Another creational design pattern called 'abstract factory" makes use of factory
method pattern.
Pitfalls
- More complex to implement. More classes involved and need unit testing.
- You have to start with Factory method design pattern from the beginning. It’s not
easy to refactor existing code into factory method pattern.
- Sometimes this pattern forces you to subclass just to create appropriate instance.
Prototype pattern
What IS a Prototype?
- We have a complex object that is costly to create. To create more Instances of such
class we use an existing instance as our prototype.
- Prototype will allow us to make copies of existing object and save us from having to
recreate objects from scratch.
Implement a Prototype
We start by creating a class which will be a prototype
- The class must implement Cloneable interface
- Class should override clone method and return copy of itself.
- The method should declare CloneNotSupportedException in throws clause to give
subclasses chance to decide on whether to support cloning.
Clone method implementation should consider the deep & shallow copy and
choose whichever is applicable.
shallow copy vs deep copy
char * Source = "Hello, world.";
'ShallowCopy' points to the same location in memory as 'Source' does. 'DeepCopy' points to a different
location in memory, but the contents are the same.
Implementation Considerations
-Pay attention to the deep copy and shallow copy of references. Immutable fields on
clones save the trouble of deep copy.
-Make sure to reset the mutable state of object before returning the prototype. It's a
good idea to implement this in method to allow subclasses to initialize themselves.
-clone() method is protected in Object class and must be overridden to be public to be
callable from outside the class.
-Cloneable is a "marker" interface, an indication that the class supports cloning.
Design Considerations
- Prototypes are useful when you have large objects where majority of state is
unchanged between instances and you can easily identify that state.
- A prototype registry is a class where in you can register various prototypes
which other code can access to clone out instances. This solves the issue of
getting access to initial instance.
Example of a Prototype
- Actually the Object.clone() method is an example of a prototype!
- This method is provided by Java and can clone an existing object, thus allowing any
object to act as a prototype. Classes still need to be Cloneable but the method does
the job of cloning object.
Pitfalls
- Usability depends upon the number of properties in state that are immutable or can be
shallow copied. An object where state is comprised of large number of mutable objects
is complicated to clone.
- In java the default clone operation will only perform the shallow copy so if you need
a deep copy you've to implement it.
- Subclasses may not be able to support clone and so the code becomes complicated as
you have to code for situations where an implementation may not support clone.
ln-A-Hurry Summary
- Think of prototype pattern when you have an object where construction of a new
instance is costly or not possible (object is supplied to your code).
- In Java we typically implement this pattern with clone method.
- Objects which have a majority of their state as immutable are good candidates for
prototypes.
- When implementing clone method pay attention to the requirement of deep or shallow
copy of object state.
- Also we’ve to insure that clone is ”initialized”; that is appropriate states are
reset before returning the copy to outside world.
Pitfalls
- A lot more complex to implement than factory method.
- Adding a new product requires changes to base factory as well as ALL implementations
of factory.
- Difficult to visualize the need at start of development and usually starts out as a
factory method.
- Abstract factory design pattern is very specific to the problem of ”product
families”.
In-A—Hurry Summary
- When you have multiple sets of objects where objects in one set work together then
you can use abstract factory pattern to isolate client code from concrete objects and
their factories.
- Abstract factory itself uses factory method pattern and you can think of them as
objects with multiple factory methods.
- Adding a new product type needs changes to base factory and all its implementations.
- Concrete factories can be singleton as we need only one instance of them in code.
- We provide client code with concrete factory instance. Factories can be changed at
runtime.
Singleton pattern
What is a Singleton?
- A singleton class has only one instance, accessible globally through a single point
(via a method/field)
- Main problem this pattern solves is to ensure that only a single instance of this
class exists
- Any state you add in your singleton becomes part of ”global state” of your
application
Implement singleton
Controlling instance creation
- Class constructor(s) must be not be accessible globally
- Subclassing/inheritance must not be allowed
Keeping track of instance
- Class itself is a good place to track the instance
Giving access to the singleton instance
- A public static method is good choice
- Can expose instance as final public static field but it won’t work for all singleton
implementations
Implement a Singleton
Two options for implementing a singleton
- Early initialization — Eager Singleton
Create singleton as soon as class is loaded
- Lazy initialization — Lazy Singleton
Singleton is created when it is first required
Implementation Considerations
- Early/Eager initialization is the simplest & preferred way. Always try to use this
approach first.
- The ”classic” singleton pattern implementation uses double check locking and volatile
field.
- The lazy initialization holder idiom provides best of both worlds, you don’t deal
with synchronization issues directly and is easy to implement.
- You can also implement singletons using enums. However due to pre-conceptions about
what an enum is, it may be a hard sell during code review especially if singleton has
mutable fields.
- If the simple solution works then use it!
Design Considerations
- Singleton creation does not need any parameters. If you find yourself in need of
support for constructor arguments, you need a simple factory or factory method
pattern instead.
- Make sure that your singletons are not carrying a lot of mutable global state.
Pitfalls
- Singleton pattern can deceive you about true dependencies! Since they are globally
accessible it’s easy to miss dependencies.
- They are hard to unit test. You cannot easily mock the instance that is returned.
- Most common way to implement Singletons in Java is through static variables and they
are held per class loader and not per JVM. So they may not be truly Singleton in an
OSGi or web application.
- A Singleton carrying around a large mutable global state is a good indication of an
abused Singleton pattern.
Summary
- Singleton pattern is used when you want to ensure that only one instance of a class
exists in application.
- In Java we achieve this by making constructor private, this also prevents inheritance
and providing a public static method which returns the singleton instance
Implementation wise we have two broad choices —
1. In eager loading singleton, we create instance as soon as class is loaded by
classloader.
2. In lazy loading singleton, we defer creation until some code actually requests the
instance.
- Always prefer the eager loading instance unless creation cost is high and start-up
time impact is noticeable.
In—A—Hurry Summary
- There are very few situations where a Singleton is really a good choice.
- Application configuration values can be tracked in a singleton. Typically these
are read from file at start and then referred to by other parts of application.
- Logging frameworks also make use of Singleton pattern.
- Spring framework treats all beans by default as singletons. In spring we don’t
have to make any changes to ensure single instance, Spring handles that for us.
Implementation Considerations
- Resetting object state should NOT be costly operation otherwise you may end up losing
your performance savings.
- Pre-caching objects; meaning creating objects in advance can be helpful as it won’t
slow down the code using these objects. However it may add-up to start up time & memory
consumption.
- Object pool’s synchronization should consider the reset time needed to avoid
resetting in synchronized context if possible.
Design Considerations
- Object pool can be parameterized to cache & return multiple objects and the acquire
method can provide selection criteria.
- Pooling objects is only beneficial if they involve costly initialization because of
initialization of external resource like a connection or a thread. Don’t pool objects
JUST to save memory, unless you are running into out of memory errors.
- Do not pool long lived objects or only to save frequent call to new. Pooling may
actually negatively impact performance in such cases.
Examples
- Using object pool for saving the memory allocation & GC cost is almost deprecated
now. JVMs & hardware are more efficient & have access to more memory now.
- However it is still a very common pattern when we are interacting with external
resources like threads, connections.
- java.util.concurrent.ThreadPoolExecutor is an example of object pool pattern which
pools threads. Even though we can directly use this class, you’ll often use it via
ExecutorSerVice interface using method like Executors like newCachedThreadPool().
- Apache commons dbcp library is used for database connection pooling. Class
org.apache.commons.dbcp.BasicDataSource in dbcp package is an example of object pool
pattern which pools database connections. This pool is commonly created and exposed via
JNDI or as a Spring bean in applications.
Pitfalls
- Successful implementation depends on correct use by the client code. Releasing
objects back to pool can be vital for correct working.
- The reusable object needs to take care of resetting its state in efficient way. Some
objects may not be suitable for pooling due to this requirement.
- Difficult to use in refactoring legacy code as the client code & reusable object both
need to be aware of object pool.
- You have to decide what happens when pool is empty and there is a demand for an
object. You can either wait for an object to become free or create a new object. Both
options have issues. Waiting can have severe negative impact on performance.
- If you create new objects when code asks for an object and none are available then
you have to do additional work to maintain or trim the pool size or else you'll end up
with very large pool.
Summary
- Objects to be pooled should provide a method to ”reset” their state so they can be
reused. This operation should be efficient as well, otherwise release operation will be
costly.
- Pool must handle synchronization issues efficiently and reset object state before
adding them to pool for reuse.
- Client code must release pooled objects back into the pool so they can be reused.
Failing to do so will break the system. Thread pools can work around this since a
thread can know when its work is done.
- Difficult to optimize as pools are sensitive to system load at runtime (demand of
pooled objects).
- Pools are good choice when the pooled objects represent a fixed quantity of
externally available resource like thread or a connection.
Structural patterns
Adapter pattern
What is Adapter?
- We have an existing object which provides the functionality that client needs. But
client code can’t use this object because it expects an object with different
interface.
- Using adapter design pattern we make this existing object work with client by
adapting the object to client’s expected interface.
- This pattern is also called as wrapper as it ”wraps” existing object.
Implement an Adapter
- We start by creating a class for Adapter
- Adapter must implement the interface expected by client.
- First we are going to try out a class adapter by also extending from our existing
class.
- In the class adapter implementation we’re simply going to forward the method to
another method inherited from adaptee.
- Next for object adapter, we are only going to implement target interface and accept
adaptee as constructor argument in adapter i.e. make use of composition.
- An object adapter should take adaptee as an argument in constructor or as a less
preferred solution, you can instantiate it in the constructor thus tightly coupling
with a specific adaptee.
Implementation Considerations
- How much work the adapter does depends upon the differences between target interface
and object being adapted. If method arguments are same or similar adapter has very less
work to do.
- Using class adapter ”allows” you to override some of the adaptee’s behaviour. But
this has to be avoided as you end up with adapter that behaves differently than
adaptee. Fixing defects is not easy anymore!
- Using object adapter allows you to potentially change the adaptee object to one of
its subclasses.
Design Considerations
- In java a “class adapter” may not be possible if both target and adaptee are concrete
classes. In such cases the object adapter is the only solution. Also since there is no
private inheritance in Java, it’s better to stick with object adapter.
- A class adapter is also called as a two way adapter, since it can stand in for both
the target interface and for the adaptee. That is we can use object of adapter where
either target interface is expected as well as where an adaptee object is expected.
Example
- The java.io.inputStreamReader and java.io.OutputStreamWriter classes are examples of
object adapters.
- These classes adapt existing InputStream/OutputStream object to a Reader/Writer
interface.
Pitfalls
- Using target interface and adaptee class to extend our adapter we can create a ”class
adapter” in java. However it creates an object which exposes unrelated methods in parts
of your code, polluting it. Avoid class adapters! It is mentioned here only for sake of
completeness.
- It is tempting to do a lot of things in adapter besides simple interface translation.
But this can result in an adapter showing different behaviour than the adapted object.
- Not a lot of other pitfalls! As long as we keep them true to their purpose of simple
interface translation they are good.
In—A—Hurry Summary
- We have an existing object with required functionality but the client code is
expecting a different interface than our object.
- A class adapter is one where adapter inherits from class of object which is to be
adapted and implements the interface required by client code. This adapter type should
be avoided.
- An object adapter uses composition . It’ll implement the target interface and use an
adaptee object composition to perform translation. This allows us to use subclasses of
adaptee in adapter.
Bridge pattern
What is Bridge?
- Our implementations & abstractions are generally coupled to each other in normal
inheritance.
- Using bridge pattern we can decouple them so they can both change without affecting
each other.
- We achieve this feat by creating two separate inheritance hierarchies; one for
implementation and another for abstraction.
- We use composition to bridge these two hierarchies.
Implement a Bridge
We start by defining our abstraction as needed by client
- We determine common base operations and define them in abstraction.
- We can optionally also define a refined abstraction & provide more specialized
operations.
- Then we define our implementor next. Implementor methods do NOT have to match with
abstractor. However abstraction can carry out its work by using implementor methods
- Then we write one or more concrete implementor providing implemention
Abstractions are created by composing them with an instance of concrete implementor
which is used by methods in abstraction.
Implementation consideration
- In case we are ever going to have a single implementation then we can skip creating
abstract implementor.
- Abstraction can decide on its own which concrete implementor to use in its
constructor or we can delegate that decision to a third class. In last approach
abstraction remains unaware of concrete implementors & provides greater de-coupling.
Design Considerations
- Bridge provides great extensibility by allowing us to change abstraction and
implementor independently. You can build & package them separately to modularize
overall system.
- By using abstract factory pattern to create abstraction objects with correct
implementation you can de-couple concrete implementors from abstraction.
Example of a Bridge
An example of bridge pattern often given is the JDBC API. More specifically the
java.sql.DriverManager class with the java.sq|.Driver interface form a bridge pattern.
What is Decorator?
- When we want to enhance behaviour of our existing object dynamically as and when
required then we can use decorator design pattern.
- Decorator wraps an object within itself and provides same interface as the wrapped
object. So the client of original object doesn’t need to change.
- A decorator provides alternative to subclassing for extending functionality of
existing classes.
Implement a Decorator
- We start with our component.
- Component defines interface needed or already used by client.
- Concrete component implements the component.
- We define our decorator. Decorator implements component & also needs reference to
concrete component.
- In decorator methods we provide additional behaviour on top that provided by concrete
component instance
- Decorator can be abstract as well & depend on subclasses to provided functionality.
Implementation Consideration
- Since we have decorators and concrete classes extending from common component, avoid
large state in this base class as decorators may not need all that state.
- Pay attention to equals and hashCode methods of decorator. When using decorators, you
have to decide if decorated object is equal to same instance without decorator.
- Decorators support recursive composition, and so this pattern lends itself to
creation of lots of small objects that add ”just a little bit” functionality. Code
using these objects becomes difficult to debug.
Desing Considerations
- Decorators are more flexible & powerful than inheritance. Inheritance is static by
definition but decorators allow you to dynamically compose behaviour using objects at
runtime.
- Decorators should act like additional skin over your object. They should add helpful
small behaviours to object’s original behaviour. Do not change meaning of operations.
Examples
- Classes in Java’s I/O package are great examples of decorator pattern.
- For example the java.io.BufferedOutputStream class decorates anyjava.io.0utputStream
object and adds buffering to file writing operation. This improves the disk i/o
performance by reducing number of writes.
Pitfalls
- Often results in large number of classes being added to system, where each class adds
a small amount of functionality. You often end up with lots of objects, one nested
inside another and so on.
- Sometimes new comers will start using it as a replacement of inheritance in every
scenario. Think of decorators as a thin skin over existing object.
In-A-Hurry Summary
- We use decorator when we want to add small behaviour on top of existing object.
- A decorator has same interface as the object it decorates or contains.
- Decorators allow you to dynamically construct behaviour by using composition. A
decorator can wrap another decorator which in turn wraps original object.
- Client of object is unaware of existence of decorator.
Composite pattern
What is Composite?
- We have a part-whole relationship or hierarchy of objects and we want to be able to
treat all objects in this hierarchy uniformly.
- This is NOT a simple composition concept from object oriented programming but a
further enhancement to that principal.
- Think of composite pattern when dealing with tree structure of objects.
Implement a Composite
We start by creating an abstract class / interface for Component
- Component must declare all methods that are applicable to both leaf and composite.
- We have to choose who defines the children management operations, component or
composite.
- Then we implement the composite. An operation invoked on composite is propagated to
all its children
- In leaf nodes we have to handle the non-applicable operations like add/remove a child
if they are defined in component.
- In the end, a composite pattern implementation will allow you to write algorithms
without worrying about whether node is leaf or composite.
Implementation Considerations
- You can provide a method to access parent of a node. This will simplify traversal of
the entire tree.
- You can define the collection field to maintain children in base component instead of
composite but again that field has no use in leaf class.
- If leaf objects can be repeated in the hierarchy then shared leaf nodes can be used
to save memory and initialization costs. But again the number of nodes is major
deciding factor as using a cache for small total number of nodes may cost more.
Design Considerations
- Decision needs to be made about where child management operations are defined.
Defining them on component provides transparency but leaf nodes are forced to implement
those methods. Defining them on composite is safer but client needs to be made aware of
composite.
- Overall goal of design should be to make client code easier to implement when using
composite. This is possible if client code can work with component interface only and
doesn’t need to worry about leaf-composite distinction.
Example
- Composite is used in many Ul frameworks, since it easily allows to represent a tree
of Ul controls.
- In JSF we have UlViewRoot class which acts as composite. Other UIComponent
implementations like UlOutput, UlMessage act as leaf nodes.
Pitfalls
- Difficult to restrict what is added to hierarchy. If multiple types of leaf nodes are
present in system then client code ends up doing runtime checks to ensure the operation
is available on a node.
- Creating the original hierarchy can still be complex implementation especially if you
are using caching to reuse nodes and number of nodes are quite high.
ln—A—Hurry Summary
- We have a parent-child or whole-part relation between objects. We can use composite
pattern to simplify dealing with such object arrangements.
- Goal of composite pattern is to simplify the client code by allowing it to treat the
composites and leaf nodes in same way.
- Composites will delegate the operations to its children while leaf nodes implement
the functionality.
- You have to decide which methods the base component will define. Adding all methods
here will allow client to treat all nodes same. But it may force classes to implement
behaviour which they don’t have.
Facade pattern
What is Facade?
- Client has to interact with a large number of interfaces and classes in a subsystem
to get result. So client gets tightly coupled with those interfaces & classes. Facade
solves this problem.
- Facade provides a simple and unified interface to a subsystem. Client interacts with
just the facade now to get same result.
- Facade is NOT just a one to one method forwarding to other classes.
Implement a Facade
We start by creating a class that will serve as a facade
- We determine the overall ”use cases”/tasks that the subsystem is used for.
- We write a method that exposes each ”use case" or task.
- This method takes care of working with different classes of subsystem.
Implementation Considerations
- A facade should minimize the complexity of subsystem and provide usable interface.
- You can have an interface or abstract class for facade and client can use different
subclasses to talk to different subsystem implementations.
- A facade is not replacement for regular usage of classes in subsystem. Those can be
still used outside of facade. Your subsystem class implementations should not make
assumptions of usage of facade by client code.
Design Considerations
- Facade is a great solution to simplify dependencies. It allows you to have a weak
coupling between subsystems.
- If your only concern is coupling of client code to subsystem specific classes and not
worried about simplification provided by a facade, then you can use abstract factory
pattern in place of facade.
Example
- The java.net.URL class is a great example of facade. This class provides a simple
method called as openStreamO and we get an input stream to the resource pointed at by
the URL object.
- This class takes care of dealing with multiple classes from the java.net package as
well as some internal sun packages.
Pitfalls
- Not a pitfall of the pattern itself but needing a facade in a new design should
warrant another look at API design.
- It is often overused or misused pattern & can hide improperly designed API. A common
misuse is to use them as ”containers of related methods”. So be on the lookout for such
cases during code reviews.
In—A—Hurry Summary
- We use facade when using our subsystem requires dealing with lots of classes 8:
interfaces for client. Using facade we provide a simple interface which provides same
functionality.
- Facade is not a simple method forwarding but facade methods encapsulate the subsystem
class interactions which otherwise would have been done by client code.
Facades are often added over existing legacy codes to simplify code usage & reduce
coupling of client code to legacy code.
Flyweight pattern
- Our system needs a large number of objects of a particular class & maintaining these
instances is a performance concern.
- Flyweight allows us to share an object in multiple contexts. But instead of sharing
entire object, which may not be feasible, we divide object state in two parts:
intrinsic (state that is shared in every context) & extrinsic state (context specific
state). We create objects with only intrinsic state and share them in multiple
contexts.
- Client or user of object provides the extrinsic state to object to carry out its
functionality.
- We provide a factory so client can get required flyweight objects based on some key
to identify flyweight.
Implementation steps
- We start by identifying ”intrinsic” & ”extrinsic” state of our object
- We create an interface for flyweight to provide common methods that accept extrinsic
state
- In implementation of shared flyweight we add intrinsic state & also implement
methods.
- In unshared flyweight implementation we simply ignore the extrinsic state argument as
we have all state withinobject.
- Next we implement the flyweight factory which caches flyweights & also provides
method to get them
- In our client we either maintain the extrinsic state or compute it on the fly when
using flyweight
Implementation Consnderations
- A factory is necessary with flyweight design pattern as client code needs easy way to
get hold of shared flyweight. Also number of shared instances can be large so a central
place is good strategy to keep track of all of them.
- Flyweight’s intrinsic state should be immutable for successful use of flyweight
pattern.
Design Considerations
- Usability of flyweight is entirely dependent upon presence of sensible extrinsic
state in object which can be moved out of object without any issue.
- Some other design patterns like state and strategy can make best use of flyweight
pattern.
Examples of a Flyweight
- Java uses flyweight pattern for Wrapper classes like java.lang.lnteger, Short, Byte
etc. Here the valueOf static method serves as the factory method.
- String pool which is maintained by JVM is also an example of flyweight. We can call
the intern() method on a String object to explicitly request this String object to be
interned. This method will returned a reference to already cached object if present or
else will create new String in cache if not present.(string.intern() is a native
method)
Pitfalls
- Runtime cost may be added for maintaining extrinsic state. Client code has to either
maintain it or compute it every time it needs to use flyweight.
- It is often difficult to find perfect candidate objects for flyweight. Graphical
applications benefit heavily from this pattern however a typical web application may
not have a lot of use for this pattern.
In—A-Hurry Summary
- We use flyweight design pattern if we need large number of objects of class where we
can easily separate out state that can be shared and state that can be externalized.
- Flyweights store only ”intrinsic” state or state that can be shared in any context.
- Code using flyweight instance provides the extrinsic state when calling methods on
flyweight. Flyweight object then uses this state along with its inner state to carry
out the work.
- Client code can store extrinsic per flyweight instance it uses or compute it on the
fly.
Proxy pattern
Lazy loading of collections by hibernate, APO based method level security, RMI/Web
service stubs are examples of real life proxy usage.
Implement
- We start by implementing proxy
- Proxy must implement same interface as the real subject
- We can either create actual object later when required or ask for one in
constructor.
- In method implementations of proxy we implement proxy’s functionality before
delegating to real object
- How to provide client with proxies instance is decided by application. We can provide
a factory or compose client code with proxies instance.
- What we are implementing above is also called as static proxy. Java also provides
”dynamic proxies”
Implement a Dynamic Proxy
We start by implementing java.lang.reflect.InvocationHandler
° Invocation handler implements invoke method which is called to handle every method
invocation on proxy
° We need to take action as per the method invoked. We’ll cache the Method instances on
image interface so that we can compare them inside invoke method
° Our invocation handler will accept same argument in constructor as needed by
constructor of real object
Actual proxy instance is created using java.lang.reflect.Proxy by client.
Implementation Considerations
- How proxy gets hold of the real object depends on what purpose proxy serves. For
creation on demand type of proxies; actual object is created only when proxy can’t
handle client request. Authentication proxies use pre-built objects so they are
provided with object during construction of proxy.
- Proxy itself can maintain/cache some state on behalf of real object in creation on
demand use cases.
- Pay attention to performance cost of proxies as well synchronization issues added by
proxy itself.
Design Considerations
- Proxies typically do not need to know about the actual concrete implementation of
real object.
- With Java you can use dynamic proxy allowing you to create proxies for any object at
runtime.
- Proxies are great for implementing security or as stand-ins for real objects which
may be a costly object that you wa nt to defer loading. Proxies also make working with
remote services/APls easy by representing them as regular objects and possibly handling
network communications behind the scene.
Examples of a Proxy
- This is one pattern where you’ll ?nd numerous examples ©
- Hibernate uses a proxy to load collections of value types. If you have a relationship
in entity class mapped as a collection, marked as candidate for lazy loading then
Hibernate will provide a virtual proxy in its place.
- Spring uses proxy pattern to provide support for features like transactions, caching
and general AOP support.
- Hibernate & spring both can create proxies for classes which do not implement any
interface. They use third party frameworks like cglib, aspect] to create dynamic
proxies (remember, Java’s dynamic proxy needs interface) at runtime.
Pitfalls
- Java’s dynamic proxy only works if your class is implementing one or more interfaces.
Proxy is created by implementing these interfaces.
- If you need proxies for handling multiple responsibilities like auditing,
authentication, as a stand-in for the same instance, then it’s better to have a single
proxy to handle all these requirements. Due to the way some proxies create object on
their own, it becomes quite difficult to manage them.
- Static proxies look quite similar to other patterns like decorator & adapter
patterns. It can be confusing to figure it out from code alone for someone not familiar
with all these patterns.
Summary
- We want a stand in or placeholder object or we want control access to our objects
method, then we can use proxy pattern.
- Proxy implements same interface as expected of real object. It delegates actual
functionality to real object. Proxies are either given real object or they create one
when needed. Some proxies talk to remote service behind the scene.
- Main usage of proxies is for:
-Protection Proxy - Control access to original object's operations
- Remote Proxy — Provides a local representation of a remote object.
- Virtual proxy — Delays construction of original object until absolutely
necessary
- In java we can also use dynamic proxies. These are created on the fly at runtime.
Behavioral patterns
Pitfalls
- There is no guarantee provided in the pattern that a request will be handled. Request
can traverse whole chain and fall off at the other end without ever being processed and
we won’t know it.
- It is easy to misconfigure the chain when we are connecting successors. There is
nothing in the pattern that will let us know of any such problems. Some handlers may be
left unconnected to chain.
In—A-Hurry Summary
- When we want to decouple sender of request from the object which handles the request,
we use chain of responsibility.
- We want this decoupling because we want to give multiple objects chance to handle the
request & we don’t know all objects before hand.
- A handler checks if it can handle the request. If it can’t then it’ll pass the
request on to next handler in chain.
- You can pass the request down the chain even if a handler handles the request. Design
pattern doesn’t prevent that from happening.
Command pattern
What is a Command?
- We want to represent a request or a method call as an object. Information about
parameters passed and the actual operation is encapsulated in a object called command.
- Advantage of command pattern is that, what would have been a method call is now an
object which can be stored for later execution or sent to other parts of code.
- We can now even queue our command objects and execute them later.
Implementation Comsiderations
- You can support ”undo” & ”redo” in your commands. This makes them really useful for
systems with complex user interactions like workflow designers.
- If your command is simple i.e. if it doesn’t have undo feature, doesn’t have any
state & simply hides a particular function & its arguments then you can reuse same
command object for same type of request.
- For commands that are going to be queued for long durations, pay attention to size of
state maintained by them.
Design considerations
- Commands can be inherited from other commands to reuse portions of code and build
upon the base.
- You can also compose commands with other commands as well. These ”macro” commands
will have one or more sub-commands executed in sequence to complete a request.
- For implementing undo feature in your command you can make use of memento design
pattern, which allows command to store the state information of receiver without
knowing about internal objects used by receiver.
Example of Command Pattern
The java.lang.Runnable interface represents the Command pattern.
- We create the object of class implementing runnable, providing all information it
needs.
- In the run method we’ll call an operation on the receiver.
- We can send this object for later execution to other parts of our application.
The Action class in struts framework is also an example of Command pattern. Here each
URL is mapped toa action class. We also configure the exact no-arg method in that class
which is called to process that request.
Pitfalls
- Things get a bit controversial when it comes to returning values & error handling
with command. ©
- Error handling is difficult to implement without coupling the command with the
client. In cases where client needs to know a return value of execution it’s the same
situation.
- In code where invoker is running in a different thread, which is very common in
situations where command pattern is useful, error handling & return values get lot more
complicated to handle.
In—A—Hurry Summary
- Command pattern allows you to treat requests for operations as objects. This allows
you to send these objects to different parts of code for later execution or to a
different thread.
- Commands typically invoke the actual operation on a receiver but contain parameters
or information needed for invocation.
- Client code is responsible for creating instances of command & providing it with
receiver and request information.
- Commands can also implement an undo feature. Here command itself stores a snapshot of
receiver.
Command pattern
Interpreter pattern
What is an Interpreter?
- We use interpreter when want to process a simple ”language” with rules or grammar.
- E.g. File access requires user role and admin role.
- Interpreter allows us to represent the rules of language or grammar in a data
structure and then interpret sentences in that language.
- Each class in this pattern represents a rule in the language. Classes also provide a
method to interpret an expression.
Implement interpreter
- We start by studying rules of the language for which we want to build interpreter
- We define an abstract class or interface to represent an expression & define
a method in it which interprets the expression.
- Each rule in the class becomes an expression. Expressions which do not need
other expressions to interpret become terminal expressions.
- We then create non-terminal expression classes which contain other
expressions. These will in turn call interpret on children as well as perform
interpretation of their own if needed.
- Building the abstract syntax tree using these classes can be done by client itself or
we can create a separate class to do it.
- Client will then use this tree to interpret a sentence.
- A context is passed to interpreter. It typically will have the sentence to be
interpreted & optionally it may also be used by interpreter to store any values which
expressions need or modify or populate.
Implementation Considerations
- Apart from interpreting expressions you can also do other things like pretty printing
that use already built interpreter in new way.
- You still have to do the parsing. This pattern doesn’t talk about how to actually
parse the language & build the abstract syntax tree.
- Context object can be used to store & access state of the interpreter.
Design Considerations
- You can use visitor pattern to interpret instead of adding interpret method in
expression classes. Benefit of this is that if you are using multiple operations on the
abstract syntax tree then visitor allows you to put these operations in a separate
class.
- You can also use flyweight pattern for terminal expressions. You’ll often ?nd that
terminal expressions can be reused.
Examples
- The java.util.regex.Pattern class is an example of interpreter pattern in Java class
library.
° Pattern instance is created with an internal abstract syntax tree, representing the
grammar rules, during the static method call compile(). After that we check a sentence
against this grammar using Matcher.
- Classes supporting the Unified Expression Language (EL) in JSP 2.1 JSF 1.2. These
classes are in javax.el package. We have javax.el.Expression as a base class for value
or method based expressions. We have javax.el.ExpressionFactory implementations to
create the expressions. javax.el.ELResolver and its child classes complete the
interpreter implementation.
Pitfalls
- Class per rule can quickly result in large number of classes, even for moderately
complex grammar.
- Not really suitable for languages with complex grammar rules.
- This design pattern is very specific to a particular kind of problem of interpreting
language.
In-a-hurry summary
- When we want to parse a language with rules we can use the interpreter pattern.
- Each rule in the language becomes an expression class in the interpreter pattern. A
terminal expression provides implementation of interpret method. A non-terminal
expression holds other expressions and calls interpret on its children.
- This pattern doesn’t provide any solution for actual parsing and building of the
abstract syntax tree. We have to do it outside this pattern.
Mediator pattern
What is mediator?
- Mediator encapsulates how a set of objects interact with each other. Due to this
encapsulation there is a loose coupling between the interacting objects.
- Typically an object explicitly knows about other object to which it wants to interact
i.e. to call a method. In mediator pattern this interaction is within the mediator
object & interacting objects only know about the mediator object.
- Benefit of this arrangement is that the interaction can now change without needing
modifications to participating objects. Changing the mediator allows to add/remove
participants in an interaction.
Implement mediator
-We start by defining mediator
- Mediators define a generic method which is called by other objects.
- This method typically needs to know which object changed and optionally the
exact property which has changed in that object.
- We implement this method in which we notify rest of the objects about the
state change.
- Mediator needs to know about all participants in the collaboration it is mediating.
To solve this problem we can either have objects register with mediator or mediator
itself can be the creator of these objects
- Depending upon your particular implementation you may need to handle the infinite
loop of change-notify-change which can result if object’s value change handler is
called for every value change whether from an external source as well as mediator
Implementation considerations
- It’s important that mediator can identify which object has sent change notification
to avoid sending that object the changed value again.
- If an object method took a very long time to process the change it can affect overall
performance of mediator severely. In fact this is a common problem in any notification
system, so pay attention to synchronization in mediator methods.
- We often end up with a complex mediator since it becomes a central point which ends
up handling all routing between objects. This can make it a very difficult to maintain
the mediator as the complexity grows.
Design Considerations
- We can extend a mediator and create variations to be used in different situations
like platform dependent interactions.
- Abstract mediator is often not required if the participating objects only work with
that one mediator.
- We can use observer design pattern to implement the notification mechanism through
which objects notify the mediator.
Examples
- Defining characteristic of mediator is: it streamlines the communication between
multiple objects. 50 a class which simply calls methods on multiple objects can’t be a
mediator confirming 100% to gof mediator definition.
- The javax.swing.ButtonGroup class is an example of mediator. It takes care of making
sure that only button in a group is selected. Participating “Buttons” notify this
mediator when they are selected.
- Purpose of front controller is to act as a central point where requests from outside
world can land and then they are forwarded to appropriate page controller, often by use
of some form of URL to class mapping.
- Front controller pattern can be thought of as a specialized version of mediator
pattern. Front controller satisfies mediator characteristics like acting as central hub
for communication between objects. It is specialized since it also handles requests
from outside system & performs lookup to find a specific controller which will handle
the request. In mediator when one object changes all others are notified!
Pitfalls
- Mediator becomes a central control object. As complexity of interaction grows,
mediator complexity can quickly get out of hand.
- Making a reusable mediator, one which can be used with multiple sets of different
objects is quite difficult. They are typically very specific to the collaboration.
Another competing pattern called Observer is much more reusable.
In—A—Hurry Summary
- When we want to decouple a group of objects which communicate with each other then we
can use the mediator design pattern.
- Each object only knows about the mediator object and notifies it about change in it’s
state. Mediator in turn will notify other objects on its behalf.
- Mediators are typically specific to a collaboration. It’s difficult to write a
reusable mediator. Observer design pattern solves this problem. However mediators are
easy to implement and extend.
Iterator pattern
What is Iterator?
- Iterator allows a way to access elements/children of an aggregate object in sequence
while hiding the actual internal data structure used.
- In Java language iterators are integral part of collection frameworks and they are
implementations of this design pattern.
- Iterators are stateful, meaning an iterator object remembers its position while
iterating.
- Iterators can become out of sync if the underlying collection is changed while a code
is using iterator.
Implement Iterator
- We start by defining Iterator interface
- Iterator has methods to check whether there is an element available in
sequence & to get that element
- We then implement the Iterator in a class. This is typically an inner class in our
concrete aggregate. Making it an inner class makes it easy to access internal data
structures
- Concrete iterator needs to maintain state to tell its position in collection of
aggregate. If the inner collection changes it can throw an exception to indicate
invalid state.
Implementation Considerations
- Detecting change to underlying data structure while some code is using an iterator is
important to notify to the client because then our iterator may not work correctly.
- Having our iterator implementation as inner class makes it easy to access internal
collection of aggregate objects.
Design Considerations
- Always prefer iterator interface so you can change the implementation without
affecting client.
- lterators have many applications where a collection is not directly used but we still
want to give a sequential access to information for example may be for reading lines
from file, from network.
Examples
- Yup! The iterator classes in Java’s collection framework are great examples of
iterator. © The concrete iterators are typically inner classes in each collection class
implementing java.util.lterator interface.
- The java.utiI.Scanner class is also an example of Iterator pattern. This class
supports InputStream as well and allows to iterate over a stream.
What is a Memento?
- When we want to store object’s state without exposing internal details about the
state then we can use memento design pattern.
- The main intent behind saving state is often because we want to restore the object to
a saved state.
- Using memento we can ask an object to give its state as a single, ”sealed” object &
store it for later use. This object should not expose the state for modification.
- This pattern is often combined with Command design pattern to provide undo
functionality in application
Implement Memento
- We start by finding originator state which is to be ”stored” in memento.
- We then implement the memento with requirement that it can’t be changed & @ outside
the originator.
- Originator provides a method to get its current snapshot out, which will return an
instance of memento.
- Another method in originator takes a memento object as argument and the originator
object resets itself to match with the state stored in memento.
Implementation Considerations
- It is important to keep an eye on the size of state stored in memento. A solution for
discarding older state may be needed to handle large memory consumption scenarios.
- Memento often ends up being an inner class due to the requirement that it must
encapsulate ALL details of what is stored in its instance.
- Resetting to previous state should consider effects on states of other
objects/services.
Design considerations
- If there is a definite, fixed way in which mementos are created then we can only
store incremental state in mementos. This is especially true if we are using command
design pattern where every command stores a memento before execution.
- Mementos can be stored internally by originator as well but this complicates the
originator. An external caretaker with fully encapsulated Memento provides you with
more flexibility in implementation.
Examples
- One great example of memento is the undo support provided by the
javax.swing.text.JTextComponent and its child classes like JTextField, JTextArea etc.
- The javax.swing.undo.UndoManager acts as the caretaker & implementations
ofjavax.swing.undo.UndoableEdit interface work as mementos. The
javax.swing.text.Document implementation which is model for text components in
swing is the originator.
Pitfalls
- In practice creating a snapshot of state may not be easy if other objects are part of
originator’s state.
- Resetting a state may not be as simple as copying references. If state change of
originator is tied with other parts of application then those parts may become out of
sync/invalid due to resetting state.
In-A—Hurry Summary
- We can use memento design pattern to take a snapshot of object’s state which can be
then used to restore object to that particular state.
- Memento itself is created such that it doesn’t expose any state stored in it to any
other class aside from the originator.
- Originator provides a method to get a memento out of it. And another method to assign
it a memento, which results in getting the originator’s state reset to the one in
memento.
- Mementos need to be saved for them to be of any use. Originator can save them but it
adds complexity.
- Memento works well with command pattern. Each commands saves a memento as part of
execution.
Observer pattern
What IS Observer?
- Using observer design pattern we can notify multiple objects whenever an object
changes state.
- This design pattern is also called as publisher-subscriber or pub-sub.
- We are defining one-to-many dependency between objects, where many objects are
listening for state change of a single object, without tightly coupling all of them
together.
- This pattern is often implemented where listener only gets notification that
”something" has changed in the object’s state. Listeners query back to find out more
information if needed. This makes it more generic as different listeners may be
interested in different states.
Implementation
- We define an interface for observer. Observer is usually a very simple interface and
defines a method used by ”subject” to notify about state change.
- Subject can be an interface if we are expecting our observers to listen to multiple
objects or else subject can be any concrete class.
- Implementing subject means taking care of handling attach, detach of observers,
notifying all registered observers & providing methods to provide state information
requested by observers.
- Concrete observers use a reference passed to them to call ”subject” for getting more
information about the state. If we are passing changed state in notify method then this
is not required.
Implementation considerations
- In some rare scenarios you may end with a circular update loop. i.e. - an update to
observable’s state results in notification being sent to a observer which then takes
some action and that action results in state change of our observable, triggering
another notification and so on. Watch for these!
- An observer object can listen for changes in multiple subjects. It becomes quite easy
to identify originator for the notification if subjects pass a reference to themselves
in notification to observer.
- Performance can become an issue if number of observers are higher and if one or many
of them need noticeable time to process notification. This can also cause pile up of
pending notifications or missed notifications.
Design Considerations
- To reduce number of notifications sent on each state update, we can also have
observers register for a specific property or event. This improves performance as on an
event, subject notifies only the interested observers instead of all registered
observers.
- Typically notifications are sent by observable when someone changes its state, but we
can also make the client code, which is changing subject’s state, send notifications
too. This way we get notification when all state changes are done. However client code
get this additional responsibility which they may forget to carry out.
Examples
- Observer is such a useful pattern that Java comes with support for this support in
Java Class Library! We have java.util.0bserver interface & java.util.0bservable class
shipped with JDK.
-Although for some reason I haven’t seen developers using these outside of
Swing
- Another commonly used example is various listeners in Java Servlet application. We
can create various listeners by implementing interfaces like HttpSessionListener,
ServletRequestListener.
- We then register these listeners with ServletContext’s addListener method. These
listeners are notified when certain events occur like, creation of a request or
addition of a value to the session.
- The notification will be sent to observers based on the event that has taken place
and the interface(s) implemented by registered observers.
Pitfalls
- Every setter method triggering updates may be too much if we have client setting
properties one after another on our observable.
- Also each update becomes expensive as no. of observers increase and we have one or
more ”slow” observers in the list.
- If observers call back the subject to find what changed then this can add up to quite
a bit of overhead.
In-a-hurry summary
- Observer pattern allows us to define one-to-many dependency between objects where
many objects are interested in state change of a object.
- Observers register themselves with the subject which then notifies all registered
observers if any state change occurs.
- In the notification sent to observers it is common to only send reference of subject
instead of state values. Observers will call the subject back for more information if
needed.
- We can also register observers for a specific event only, resulting in improved
performance of sending notifications in the subject.
- This design pattern is also known as publisher-subscriber pattern. Java messaging
uses this pattern but instead of registering with subject, listeners register with a
JMS broker, which acts as a middleman.
State pattern
Pitfalls
- Since client code configures context object with appropriate strategy object, clients
know about all implementations of strategy. Introducing new algorithm means changing
client code as well.
In-A-Hurry Summary
- Strategy pattern allows us to encapsulate algorithms in separate classes. The class
using these algorithms (called context) can now be configured with desired
implementation of an algorithm.
- It is typically the responsibility of client code which is using our context object
to configure it.
- Strategy objects are given all data they need by the context object. We can pass data
either in form of arguments or pass on context object itself.
- Strategy objects typically end up being stateless making them great candidates for
flyweight pattern.
- Client code ends up knowing about all implementations of strategy since it has to
create their objects.
Template pattern
Pitfalls
- Tracking down what code executed as part of our algorithm requires looking up
multiple classes. The problem becomes more apparent if subclasses themselves start
using inheritance themselves to reuse only some of the existing steps & customize a
few.
- Unit testing can become a little more difficult as the individual steps may require
some specific state values to be present.
In-A-Hurry Summary
- Template method allow us to define a skeleton of an algorithm in base class. Steps of
algorithm are defined as abstract methods in base class.
- Subclasses of our abstract class will provide implementation of steps. This way we
can have different implementations for same algorithm.
- Client will create object of any of the concrete subclasses and use the algorithm.
- Factory method design pattern is often implemented as part of template method design
pattern.
- One drawback of template method is algorithm implementation is now spread across
multiple classes so it makes it slightly difficult to understand.
Visitor pattern
Pitfalls
- Often visitors need access to object’s state. So we end up exposing a lot of state
through getter methods, weakening the encapsulation.
- Supporting a new class in our visitors requires changes to all visitor
implementations.
- If the classes themselves change then all visitors have to change as well since they
have to work with changed class.
- A little bit confusing to understand and implement.
In-a-hurry Summary
- Visitor pattern allows to add new operations that work on objects without modifying
class definitions of these objects.
- Visitors define class specific methods which work with an object of that class to
provide new functionality.
- To use this pattern classes define a simple accept method which gets a reference to a
visitor and inside this method, objects class method on visitor which is defined for
that specific class.
- Adding a new functionality means creating a new visitor and implementing new
functionality in that class instead of modifying each class where this functionality is
needed.
- This pattern is often used where we have an object structure and then another class
or visitor itself iterates a over this structure passing our visitor object to each
object.
Null pattern