720 likes | 896 Views
Design Patterns. Agenda. Good practices again Pattern - what is it ? Definition, explanation, examples Classifications Which aspect of design is easy to change by pattern? Review of patterns (GoF). Good practices.
E N D
Agenda • Good practices again • Pattern - what is it ? • Definition, explanation, examples • Classifications • Which aspect of design is easy to change by pattern? • Review of patterns (GoF)
Good practices • Programming to interface not to implementation. Client should always call the abstraction (interface) and not the exact implementation. • Type – interface – contract • Implementation – class • Have loose coupling. Use rather aggregation than inheritance • delegations
Pattern – definition ? • Patterns provide simple, elegant solutions to recurring design problems. • Name for collecting advices and knowledge about problem and its solutions. • Changing view from code reuse to knowledge reuse • Shorthand to conclusions about common design problems and techniques
Template method Pattern: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
Template method Participants and cooperation: AbstractClass(DataObject) • defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm • implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects. • ConcreteClass(CustomerDataObject) • implements the primitive operations to carry out subclass-specific steps of the algorithm
Template method - example • Print(StreamWriter dst) • { • PrintHeader(dst); • PrintBody(dst); • PrintFooter(dst) • }
Template method When: - When can separate fixed part / variations of algorithms - Common behavior can/should be separated and placed in base class Consequences: • Behavior of class has to be determined in the compilation time – cannot be changed in the rune-time • We can define simply/default implementations in a base class or not • The access to primitives can be limited by protected accessor Implementation remarks • Possible access limitation • The number of primitive operations should be rater kept on relatively low level – combinatorial explosion Known/common use cases: • Most of abstract classes Related patterns: • Strategy
Strategy (alias Policy) Pattern: Define a family of algorithms, encapsulate each one, and make them interchangeable.
Strategy - example ... val = calc.CalculateTotal(...) ...
Strategy When: • We need many, similar variants of a particular algorithm • We need to hide details of algorithm (e.g. additional parameters) • There are many conditional behaviors – many switches/conditionals are used in multiple places Consequences: • Behavior as well as implementation can be changed in the rune-time • Good alternative for multiple if blocks - we can simply once choose a particular implementation of behavior • No necessity to define many subclasses • We can create the families of connected algorithms • Context has to know about multiple strategies or has to be parametrized with a strategy • Increased number of objects Implementation • Interfaces, strategies as template parameters • If object of strategy is optional the Context may be much simpler Related patterns: • Template method • Flyweight
What is important • Pattern is not a ready to use library but rather a way with some knowledge about an end of the way. Usually there are many ways to implement a particular pattern. • Learning about patterns means more than memorizing pattern names and the mechanics of using the patterns. Learning the benefits and the drawbacks of patterns is even more important. • Given implementation (classes) is a sample only, not the only possible, even not the best one.
What is even more important • Patterns are not obligatory. Often, to avoid overdesign, we will start from very simple solution and (if necessary) refactor it to (or towards) of a pattern. • When we choice the pattern we should consider problem and acceptable solution. However, we should concern how system might change in the future. • We have to balance between overdesign and flexibility. • Some patterns are considered as overused – e.g. Singleton (antipattern?)
Advantages • Communication and common language • All related knowledge in one place • Forces • Related patterns • Solutions • Way to increase separation of what varying from what stay the same • We can spend (at the beginning) more time on the level of design without technical details of realization • We can anticipate some consequences of particular solution
Disadvantages • Potential overdesign – in many cases simple solution is enough • Solution TDD: Tests -> Code -> Refactoring • Thinking of patterns that there is a closed, inflexible, definitive set and we are not allowed to go out from it. (people still discover new patterns ;) ) • Any real project is fitted to certain pattern. We have to adopt patterns to particular application
Patterns classification • Fundamental • Creational - deal with the creation of objects;encapsulate knowledge about which class we use and how objects are created. • Structural - ease the design by identifying a simple way to realize relationships between entities; encapsulate knowledge about interface and inner structure. • Behavioral - that identify common communication patterns between objects and realize these patterns; encapsulate knowledge about algorithms and behavior. • Enterprise
Fundamental • Delegation pattern: an object outwardly expresses certain behavior but in reality delegates responsibility • Functional design: assures that each modular part of a computer program has only one responsibility and performs that with minimum side effects • Interface pattern: method for structuring programs so that they're simpler to understand
Creational • Abstract factory pattern: centralize decision of what factory to instantiate • Factory method pattern: centralize creation of an object of a specific type choosing one of several implementations • Builder pattern: separate the construction of a complex object from its representation so that the same construction process can create different representations • Lazy initialization pattern: tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed
Creational • Object pool: avoid expensive acquisition and release of resources by recycling objects that are no longer in use • Prototype pattern: used when the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) is prohibitively expensive for a given application • Singleton pattern: restrict instantiation of a class to one object
Structural • Adapter pattern: 'adapts' one interface for a class into one that a client expects • Aggregate pattern: a version of the Composite pattern with methods for aggregation of children • Bridge pattern: decouple an abstraction from its implementation so that the two can vary independently • Composite pattern: a tree structure of objects where every object has the same interface • Decorator pattern: add additional functionality to a class at runtime where sub classing would result in an exponential rise of new classes
Structural • Facade pattern: create a simplified interface of an existing interface to ease usage for common tasks • Flyweight pattern: a high quantity of objects share a common properties object to save space • Proxy pattern: a class functioning as an interface to another thing • Private class data pattern: restrict accessor/mutator access
Behavioral • Chain of responsibility pattern: Command objects are handled or passed on to other objects by logic-containing processing objects • Command pattern: Command objects encapsulate an action and its parameters • Interpreter pattern: Implement a specialized computer language to rapidly solve a specific set of problems • Iterator pattern: Iterators are used to access the elements of an aggregate object sequentially without exposing its underlying representation • Strategy pattern: Algorithms can be selected on the fly
Behavioral • Mediator pattern: Provides a unified interface to a set of interfaces in a subsystem • Memento pattern: Provides the ability to restore an object to its previous state (rollback) • Null Object pattern: Designed to act as a default value of an object • Observer pattern: aka Publish/Subscribe or Event Listener. Objects register to observe an event which may be raised by another object • State pattern: A clean way for an object to partially change its type at runtime
Behavioral • Specification pattern: Recombinable Business logic in a boolean fashion • Template method pattern: Describes the program skeleton of a program • Visitor pattern: A way to separate an algorithm from an object • Single-serving visitor pattern: Optimize the implementation of a visitor that is allocated, used only once, and then deleted • Hierarchical visitor pattern: Provide a way to visit every node in a hierarchical data structure such as a tree.
Creation – why....? • Why to not use the constructor ? • All the constructors have identical names • Have differ by parameters (number/types) • Constructors should have not call virtual functions • There may be a lot of variables, so, to avoid problems with a long, long list of parameters we have to define the structures/classes to aggregate them ... for purpose of passing the values to the constructor.
Creation method? • Instead • new Loan(commitment, riskRating, maturity) • new Loan(commitment, riskRating, maturity, expiry) • new Loan(commitment, outstanding, riskRating, maturity, expiry) • new Loan(capitalStrategy, commitment, outstanding, riskRating, maturity, expiry) • Better: • new Loan(capitalStrategy, commitment, outstanding, riskRating, maturity, expiry) • CreateTermLoan(commitment, riskRating, maturity) • CreateTermLoan(capitalStrategy, commitment, outstanding, riskRating, maturity) • CreateRevolver(commitment, outstanding, expiry) • CreateTermLoan(capitalStrategy, commitment, expiry, maturity) • CreateRCTL(commitment, outstanding, riskRating, maturity, expiry) • CreateRCTL(capitalStrategy, outstanding, riskRating, maturity, expiry) • Very general approach similar to Factory Method
Factory method • Do we need to have derived classes figure out what to instantiate and decouple client from instantiated class? • Sometimes more general pattern is discussed: Creation method
Abstract factory • Do we need to create families of objects? • Consistence of products. • Introduction new type of product to family require refactoring for whole factories class hierarchy • Introduce new class for each new family of object.
Prototype • Do we have too many classes to instantiate / or is the object creation a cumbersome process? • Is object type specified at runtime? • Client configure one prototype and then use it for obtaining copies.
What about ...? • Creation of complex object hierarchies eg. dictionary tries • Limitation of instances • Global access to the particular objects
Builder • Do we need to create object in several steps? • Decoupling builing algorithm from assemblies.
Singleton • Do we need to limit number of objects of a class? • Centralized access to object.
Do you need the ready to code example ...? • http://www.dofactory.com/Patterns/PatternSingleton.aspx#_self2 • Do not overuse the singleton conception ...
Another issues ... Lets assume we have a large object structure e.g. tree of objects, dictionaries etc. • How to provide easy access to the whole structure e.g. search etc? • How to provide the interface to play with particular small pieces?
Fasade • Do we want simplify, beautify or OO-fy an existing class or subsystem? • We loss direct access to subsystems.
Iterator • Do we want to separate collection from client that's using? • Access to spreaded information
Visitor • Do we have new tasks that we will need to apply to our existing classes? • Which class from class hierarchy are modified most often? • Visitor fit the best for stable class structure and large, varying set of unconnected different operation performed on objects. • Hard to add new class ConcreteElement. It leads to modifications all class hierarchy for visitors.
Structure ...? • if we need to control access to the object • if we need to add/change the functionality but the object already exists/we do not create this object • or maybe we need to access the object on remote environment ... sounds similar ?
Proxy • Do we need to optionally add some new functionality to something that already exists? Do we need to control how an object is accessed (eg. copy on write)?
Structure ...? • Lets assume that we have a good algorithm but client would like other interface than our class offers. • Shall we change the implementation we have ? If not - what should we to do ? • We have a class/subclasses but we would like to add some new functionality. • Our class is pretty large we would like to split it but how to deal with the change of interface ?
Adapter • Do we have the right stuff but wrong interface? • Two way adaptation classes/objects
Decorator • Do we need multiple additional functions we may need to apply, but which and how many we add varies, without sub classes? • Growing number of small objects.
Structure ...? • What about the situation when we have a lot of small objects (e.g. Strategy)
Flyweight • Do we have too many part objects? • Cost of storage ary high due to count of objects? • Majority of object state can be transfer out side object (outer state can be marge in shared objects)? • Identity of objects is not important for system? • Decresing count of objects. • Decrising size of objects. • Calculating or storing inner state?