This tutorial is a concise overview of Design patterns. The purpose of this tutorial is to show that the two key notions behind OO programming are: design with reuse and design for reuse. To that extent, Design patterns is an informal software design method that singles out code architectural styles (a.k.a. patterns). Design patterns may preexist in software libraries and, therefore, they are reused “as is” (design with reuse) with the least possible adaptations. On the other hand, new code has to be organized by following schemes promoted by Design patterns (design for reuse).
Economical quality features (direct impact)
- Reusability
- Maintainability
- Reliability (correctness)
Social quality features (direct impact)
- Reliability (integrity, safety-critical applications versus error-free applications that maintain corporate identity)
- Scalability (including performance)
- Security
- Ease of use
Other key quality features
- Portability (including interoperability)
- Sustainability
- Etc.
Design with reuse encompasses the search, the selection and the controlled integration of trusted software pieces with cost-effectiveness and time-effectiveness (productivity...). The reuse process is a suite of three key phases, namely analysis, design and programming as it follows.
Analysis
As shown above, white rectangles are “business objects” coming from business analysis.
Design
At design time, business objects are assigned to library components (gray rectangles) in order to elaborate on how business services may rely on technical functions in these components.
Programming
At programming time, glue code allows the effective connection. Often, library components cannot be reused “as is”. Dots in gray rectangles mimic such an adaptation so that library components become fully integrable.Design for reuse (see Template design pattern) Composite design pattern Archetype
template<typename T> class Role : public set<T*, less<T*> > { template<typename T> class Composite : public Role<T> { … template<typename T> class Component : public Role<T> { … template<typename Whole, typename Part> class Aggregation; template<typename Whole, typename Part> class _Aggregation { friend class Aggregation<Whole, Part>; … template<typename Whole, typename Part> class Aggregation { private: static map<string, _Aggregation<Whole, Part>, less<string> > _aggregation; string _name; … class Network_element { }; class Manager; class Agent { public: virtual Role<Manager> manager() const = 0; virtual Composite<Network_element> managed_objects() const = 0; }; class Manager { public: virtual Role<Agent> agent() const = 0; virtual Role<Network_element> accessed_objects() const = 0; };
Data Access Object (DAO) design pattern The Data Access Object design pattern (a.k.a. DAO or DTO, which stands for Data Transfer Object) rules the way of accessing data in databases. For example, greenDAO is devoted to the Android system to manage embedded databases. In common Java, Java Persistence API (JPA) is a standardized persistence framework in the common Java Virtual Machine (JVM); JPA itself encapsulates the Java DataBase Connectivty (JDBC) standard.
Archetype (Java)
- “Entity Beans” in the Enterprise JavaBeans™ (EJB) technology or Plain Old Data Objects (POJOs) in Hibernate
Archetype (C++)
namespace New_York_City_Penitentiary { inline namespace DAOs { class Criminal_case { ... }; … } namespace Nominal { class Prisoner { const std::string _prison_file_number; std::string _given_name; std::string _surname; std::tm _date_of_birth; std::string _place_of_birth; std::tm _date_of_incarceration; const Criminal_case * _incarceration_main; public: explicit Prisoner(const std::string&); bool operator<(const Prisoner&) const; // For 'std::set' std::string get_prison_file_number() const; std::string get_given_name() const; void set_given_name(const std::string&); const std::string& get_surname() const; void set_surname(const std::string&); std::tm get_date_of_birth() const; void set_date_of_birth(const std::tm&); std::string get_place_of_birth() const; void set_place_of_birth(const std::string&); std::tm get_date_of_incarceration() const; void set_date_of_incarceration(const std::tm&); const Criminal_case* get_incarceration_main() const; void set_incarceration_main(const Criminal_case *); std::string toString(); }; class Prisoner_hash { // For 'std::unordered_set' public: std::size_t operator()(Prisoner const&); }; } … }
Façade design pattern Archetype (Java)
- Session beans in the Enterprise JavaBeans™ (EJB) technology
Factory design pattern Archetype (C++)
// '.h' file: template<typename O, typename P> class Factory { public: static O GetInstance(const P& p) { O o(p); return o; } // Deletion of 'o'... static O GetClone(O& o) { // Overloads raise combinatory problems in case of multiple anonymous types... // Change 'o' in some way... O _o = o; // 'O _o(o);' return _o; } // Deletion of '_o'... static O GetClone(const O& o) { // Overloads raise combinatory problems in case of multiple anonymous types... // Change 'o' in some way... O _o = o; // 'O _o(o);' return _o; } // Deletion of '_o'... static O GetClone(O&& o) { // Change 'o' in some way... O _o(std::forward<O>(o)); // Forwards lvalue as either lvalue or as rvalue, depending on 'O'... return _o; } // Deletion of '_o'... }; class Person : public Factory<Person, std::string> { … }; // '.cpp' file: Person someone; someone = Person::GetInstance("someone"); // Move assignment
Observer design pattern Archetype
- Observer historically embodies the principles of state change and notification behind the Model-View-Controller programming paradigm. One of the Java native supports of Observer is deprecated. Indeed, both the
java.util.Observable
class and thejava.util.Observer
interface aim at being forgotten…- Instead, the Java native supports of Observer in
java.beans
still persist through these two classes:«class»java.util.EventObject
⇧ «class»Two interfaces also play a great role in the Java native supports of Observer injava.util.PropertyChangeEvent
java.beans
:«interface»java.util.EventListener
⇧ «interface»java.beans.PropertyChangeListener
Example (run indicator -as part of a programmable thermostat- in JavaBeans™)
public interface Run_indicator_client extends java.beans.PropertyChangeListener {…} … public class Programmable_thermostat extends … implements Run_indicator_client, … {…} … public class Run_indicator implements java.io.Serializable { … private final java.beans.PropertyChangeSupport _propertySupport = new java.beans.PropertyChangeSupport(this); public Run_indicator(Run_indicator_client programmable_thermostat) throws Statechart_exception { … _propertySupport.addPropertyChangeListener(programmable_thermostat); } public void off() throws Statechart_exception { _Run_indicator.fires(_Something_on, _Everything_off); _Run_indicator.run_to_completion(); String status = _Run_indicator.current_state(); _propertySupport.firePropertyChange("Run indicator status", _status, status); _status = status; } … }
Singleton design pattern Archetype (Java)
- Singleton session beans in the Enterprise JavaBeans™ (EJB) technology
Archetype (C++)
class Global_exception_management { // No instance required! public: static void my_unexpected(); static void my_terminate(); };
Template design pattern Archetype
- Graphical User Interface (GUI) libraries
Case study (requirements)
Requirements, first part
Requirements, second part
Case study (analysis)
Analysis model sample
Case study (design for reuse)
Bad design (1/2)
Bad design (2/2)
In fact, the two bad designs above do not favor maintainability at the time a third norm calculation would be introduced in the application. To better manage this potential evolution, the two good designs below are based on the Template design pattern. Namely theActivity card computation
(generic) class is abstract with two concrete (generic) subclasses,Activity card comp. quad.
andActivity card comp. max.
that both implement thenorm
abstract function inActivity card computation
.
Good design (inheritance)
Good design (composition)
Case study (design with reuse)
Programming model sample (reuse through composition)
![]()
Programming model sample (reuse through multiple inheritance)
Implementation in C++
![]()
template<typename T> class Activity_card_computation { ... protected: std::vector<T> _implementation; public: ... // Constructors and destructors here… virtual double norm() const = 0; double norm_addition(const Activity_card_computation& v) const { return (*this +v).norm(); } double norm_subtraction(const Activity_card_computation& v) const { return (*this -v).norm(); } double lambda_norm(const double lambda) const { return std::fabs(lambda) * norm(); } ... };
Implementation in Java
![]()
abstract public class Activity_card_computation<T extends Number> extends Number { ... protected java.util.Activity_card_computation<Number> _implementation; ... // Constructors here… abstract public double norm(); public double norm_addition(final Activity_card_computation<T> v) { return this.plus(v).norm(); } public double norm_subtraction(final Activity_card_computation<T> v) { return this.minus(v).norm(); } public double lambda_norm(final double lambda) { return Math.abs(lambda) * norm(); } ... }