Software Patterns Well-Proven Software Design Experience ARTEM TABALIN
Software Patterns!Well-Proven Software Design Experience!
ARTEM TABALIN!
Software Pattern!What. Why Use. Classification.!
What is a Pattern!!A pattern is a general reusable solution to recurring
software design problem, arising in a specific context.!
Documents existing well-proven design experience!
!
Pattern Consists of!
Context!A situation giving a rise to a problem!
Problem!The recurring problem arising in that context!
Solution!A proven resolution of the problem!
!
!
C
P
S
Why Use Patterns!
• Specify abstractions above the level of single class!
• Create common vocabulary for communication!
• Provide means for documenting architectures!
• Assure support of defined properties!
• Help to manage software complexity!
• Allow to build complex software
Classification!
• Architectural PatternsSystem-wide structuring principles!MVC, Layers, Pipes & Filters!
• Design PatternsSchemes for refining subsystems!Abstract Factory, Adapter, Strategy!
• Idioms!Low-level close to implementation!JavaScript: module, self-defining functions!!
Other Categories!
• General Responsibility Assignment (GRASP) !Low Coupling, High Cohesion, Pure Fabrication!
• EnterpriseDomain Model, Data Mapper, Lazy Load, Repository!
• Concurrency!Monitor Object, Read-Write Lock, Reactor!
• Distributed Computing!Broker, Data Transfer Object!!
GRASP!General Responsibility Assignment Software Patterns!
What is GRASP!
General principles for assigning responsibility to classes and objects in object-oriented design!
!
!
• Creator!
• Low Coupling!
• High Cohesion!
• Information Expert!
• Controller!
• Polymorphism!
• Indirection!
• Pure Fabrication!
• Protected Variations!
!
Creator!
Who should create a class A?!
Class B should create A if!
• B contains A
• B records A
• B closely uses A
• B has initializing data for A
For complex instantiation use Factory!
P
S
Creator!
Order OrderRegister
OrderLine Who should instantiate OrderLine?
Low Coupling!
How to reduce the impact of changes?!
Assign the responsibility to maintain low coupling!
• Localized changes!
• Easier to understand!
• Easier to reuse!
P
S
OrderRegister
+MakePayment()
Low Coupling!
Order
Who should create Payment?
Payment
High Cohesion!
How to keep classes focused and understandable?!
Assign the responsibility to maintain high cohesion!
• Easier to understand!
• Easier to reuse!
• Easier to maintain!
• Lower coupling!
!
P
S
OrderRegister
+MakePayment()
High Cohesion!
Order
Who should create Payment?
Payment
Information Expert!
Whom to assign the responsibility for an operation?!
Assign the responsibility for an operation to the class that has all necessary information to accomplish it!
• Better encapsulation!
• Higher cohesion!
P
S
SaleReporter
+PrintTotal()
Information Expert!
Order
OrderLine
Who should calculate order total? Product
Controller!
Who should handle events from UI?!
Assign the responsibility to the class representing use case scenario ![UseCase](Handler | Controller | Session)!
• Separate UI from application logic!
• Increase reusability!
P
S
OrderView
Controller!
Order
Who should save Order? OrderController
Polymorphism!
How to handle different behavior based on type?!
Assign responsibilities for the behaviors with polymorphic methods in types !
• Easier to extend (even without changing the clients)
P
S
OrderRegister
+RegisterOrder()
Polymorphism!
Avoid direct type check
TermimalRegister
+RegisterOrder()
ImportRegister
+RegisterOrder()
Indirection!
How to avoid direct coupling between two classes?!
Assign the responsibility for the communication between components to intermediate object!
• Lower coupling!
“All problems in computer science can be solved by another level of indirection”!
David Wheeler!
P
S
Order
+GetTotal()
Indirection!
<<remote>>
Tax Service
How retrieve tax info from remote service? TaxServiceGateway
Pure Fabrication!!
Whom to assign the responsibility not violating low coupling and high cohesion principles?!
Assign the responsibility to an artificial class not belonging to domain!
• Lower coupling!
• Higher cohesion!
P
S
Order
Pure Fabrication!
DataBase Driver
Who should save Order to DB? OrderRepository
Protected Variations!
How to protect components from outside variations?!
Identify the points of variations and assign the responsibility to ensure stable interface around them!
• Easier to extend!
• Lower coupling!
• Lower cost of changes!
P
S
Protected Variations Techniques!
• Data-Driven Design!Reading metadata at runtime!
• Service Lookup !Lookup up service class at runtime reading from configuration!
• Interpreter-Driven Design!Support language and executing external scripts !
• Liskov Substitution Principle!Interface implementers can be used interchangeably!
!
Architectural Patterns!Structure. Interactive Systems. Adaptive Systems. !
Structural Patterns!
• Layers!UI, Services, Business Logic, Data Access!
• Pipes and Filters!Chain of filters connected with pipes!
• Service-Oriented Architecture (SOA)!Set of independent services!
• Microservices!Set of small independently deployed services!!!
!
Layers!
A large system requiring decomposition!
How to organize work with low- and high-level issues?!low-level: database, sensors, hardware !high-level: user interface!
Divide system into appropriate amount of layers placing them on top of each other!Usage: Enterprise Applications, OS!
P
S
C
Layers!Presentation Layer
ClientList.cshtml
Business Logic Layer (BLL) Client.cs
Data Access Layer (DAL) ClientRepository.cs
Application Logic Layer ClientController.cs
Pipes and Filters!
Processing data streams!
How to build flexible configurable system for processing and transforming data streams?!requirement: future enhancements!
Divide the task into sequential processing steps. The output of each step is the input for the next.!Usage: Workflow Processor, Compiler, UNIX Shell!
P
S
C
Pipes and Filters!
Lexical Analyzer
UTF-8 code
Token stream
Syntax Analyzer
Semantic Analyzer
Abstract syntax tree
Intermediate Code
Generator
Annotated syntax tree
Code Optimizer
Intermediate code
Code Generator
Optimized code
Machine code
Service-Oriented Architecture!
A large system requiring high integrability!
How to build system architecture to provide high integration capabilities and heterogeneous Uis?!requirement: different clients (browser, mobile app, public API)!
Divide system into set of independent services communicating by contract over network.!Tech: Web Services, REST, WCF, Apache Thrift!
P
S
C
Service-Oriented Architecture!
Service Directory
Service Service
Customer
Invokes
Interactive Patterns!
• MVC!Model-View-Controller!
• MVP!Model-View-Presenter!
• MVVM!Model-View-ViewModel!
• PAC!Presentation-Abstraction-Control!!!
!
Model-View-Controller!
Interactive application with flexible user interface!
How to build a system with complex user interface separated from core functionality!requirement: easily-changeable UI!
Divide application into three areas: input (Model), output (View) and processing (Controller)!
P
S
C
Model-View-Controller!
View
Model Controller Manipulates
User Interaction
Model-View-Presenter!
View
Model Presenter
Manipulates
Fires events
User Interaction
Model-View-ViewModel!
View
Model ViewModel
Updates
Fires events
User Interaction
Adaptive Patterns!
!• Microkernel!
Minimal core separated from other modules!
• Reflection!Base level and configuring behavior meta level!!
!
Microkernel!
Developing several applications, using the same core!
How to build an application platform requiring continuous evolution and high-extensibility?!!
Encapsulate core services in a microkernel, allowing other components to communicate with each other!
P
S
C
Microkernel!App
Call service
App App
Adapter
Microkernel
Internal Server
Internal Server
Internal Server
External Server
External Server
External Server
Send request
Execute service
Activate service
Reflection!
Build a system supporting self-modification!
How to build a system which allows to change its structure and behavior dynamically?!!
Introduce two levels: base level with application logic and meta level with data about structure and behavior!
P
S
C
Reflection!
ComponentA ComponentB
Base Level
MetaObjectA MetaObjectB
Meta Level
MetaObject Protocol
Enterprise Patterns!Domain Logic. Data Source. Web Presentation.!
Domain Logic Patterns!
Development of an enterprise application!
How to structure business logic of the application?!
• Transaction Script!Simple procedural approach to data processing!
• Domain Model!Object-oriented domain logic modeling!
• Table Module!Data store table-oriented modeling!
P
C
S
TransactionScript
+run()
Transaction Script!
CalculateTaxTS
+new(orderID) +run()
MakePaymentTS
+new(product[], quantity[]) +run()
May contain SQL-queries in code
Payment
+discount +contract: Contract
Domain Model!
Differs from DB structure
Order
+total()
OrderLine
+sum()
Product
+price
1 1
*
1
1
1
Payment
+new(DataSet) +GetDiscount(paymentId)
Table Module!
Map of DB structure May consist of static
methods
Order
+new(DataSet) +GetTotal(orderId)
OrderLine
+new(DataSet) +GetSum(orderLineId)
Product
+new(DataSet) +GetPrice(productId)
Data Source Patterns!
Development of an enterprise application!
How to organize the access to the database?!
• Table/Row Data Gateway!Provide class representing each table (table row) of database!
• Active Record!Add data manipulation methods to domain model objects!
• Data Mapper!Add a layer of mappers to decouple model and data scheme!
P
C
S
OrderGateway
+findAll(): RecordSet
+find(id): RecordSet
+update(id, date, total)
+insert(date, total)
+delete(id)
Table Data Gateway!
sql = “SELECT * FROM Orders”;
cmd = new DbCommand(sql, cn);
return cmd.GetRecordSet();
id details
1
2 Orders
- Use with Table Module
- DTO over RecordSet
- Views over Tables
OrderGateway
+customerId: long
+date: datetime
+findAll(): OrderGateway[]
+find(id): OrderGateway
+update()
+insert()
+delete()
Row Data Gateway!
sql = “SELECT * FROM Orders”;
cmd = new DbCommand(sql, cn);
return load(cmd.GetRecordSet());
id details
1
2 Orders
- No domain logic
- Finder class for finds
- Auto-generated code
Order
+customerId: long
+date: datetime
+findAll(): Order[]
+find(id): Order
+update()
+insert()
+delete()
+getTotal(): decimal
Active Record!
sql = “SELECT * FROM Orders”;
cmd = new DbCommand(sql, cn);
return load(cmd.GetRecordSet());
id details
1
2 Orders
- Has domain logic
- Couples domain to DB
- Use for simple logic
OrderMapper
+findAll(): Order[]
+find(id): Order
+update(Order)
+insert(Order)
+delete(Order)
Data Mapper!
id details
1
2 Orders
- Decouples domain from DB
- Usually used with Domain Model
- Better use external ORM
Order
+customerId: long
+date: datetime
+getTotal(): decimal
Unit of Work!
Organize optimal access to data source!
How to manage object changes to avoid multiple database calls and shorten transaction span?!!
Maintain the list of affected objects, flushing the changes at once considering consistency issues!
P
S
C
UnitOfWork
+registerNew(object)
+registerDirty(object)
+registerClean(object)
+registerDeleted(object)
+commit()
Unit of Work!
- Handles changes on commit
- Ensures data consistency
- One Unit of Work per session
Order
+new()
+setTotal(decimal)
OrderMapper
+update(Order)
+insert(Order)
+delete(Order)
OrderController
+registerOrderAction(request)
Registers changes Applies changes
UnitOfWork.init();
OrderService.RegisterOrder();
UnitOfWork.current().commit();
Repository!
Organize access to data source!
How to simplify domain objects accessing interface to work with them in collection-like way?!!
Create intermediate abstraction layer between domain and data mappers acting like in-memory collection!
P
S
C
IRepository<T>
Find(Criteria): IList<T> Insert(obj: T) Update(obj: T)
Delete(obj: T)
Repository!
EntityFrameworkReposity<T>
-context: DbContext #Table: DbSet<T>
OrderReposity
#Table: DbSet<Order>
- Acts like in-memory collection
- Criteria allows to build queries
- Mock to in-memory in unit test
Web Controller Patterns!
Web application with MVC architecture!
How to handle requests in a web application?!
• Page Controller!A controller per each web app page!
• Front Controller!Single controller for the entire web app!!
P
C
S
Page Controller!
View
[Display HTML]
Model
[Domain Logic]
PageController
action(Request, Response)
- Handles web requests to a page
- Creates model and processes data
- Chooses view to display
Front Controller!
Command
+new(Request) +process()
OrderListAction
+pocess()
FrontController
handleGet(Request, Response)
handlePost(Request, Response)
- Accepts all web requests
- Dispatches request to a command
- Simplifies authorization and logging
OrderAddAction
+pocess()
Web View Patterns!
Web application user interface!
How to render resulting HTML responding to request?!
• Template View!HTML template with markers for rendering logic!
• Transform View!Transform domain data into HTML markup!
• Tow Step View!Turn domain data into HTML markup in two steps!
P
C
S
Template View!
Order
+lines: List<OrderLine> +total(): decimal
OrderHelper
lineDetail(line): String totalStr(): String
- Usually server page (php, aspx, jsp)
- Avoid logic in template
- Put all logic in helper
OrderDetails.tmpl
… <ul {foreach(l in lines)}> <li>{lineDetail(l)}</li> </ul> <b>{totalStr()}</b> …
Transform View!
Order
+lines: List<OrderLine> +total(): decimal
Transformer
+transformOrder(ord)
- Domain objects => xml (json) => html
- XSLT transformation is dominant
- Harder to write, easier to test
HTML read create
Two Step View!
Order
+lines: List<OrderLine> +total(): decimal
OrderStageFirst
+renderOrder(ord) +renderOrderLine(line)
- Domain objects => logical view => html
- Gives flexibility in result html formatting
- Allows several target representations
HTML
read create
OrderView
+lines: List<Row> +total(): Field
OrderStageSecond
+renderView(orderView) +renderRow(orderRow)
read create
Design Patterns!Creational. Structural. Behavioral.!
Creational Patterns!
• Abstract Factory!Provides interface for creating families of related objects!
• Builder!Separates construction of complex object from representation!
• Factory Method!Defines method to create instance not specifying exact class!
• Singleton!Ensures a class has only one instance with global access to it!!!
!
Abstract Factory!
PlatformWidget
+render()
<<interface>>
WidgetFactory
+createWidget(): Widget
Allows supporting several platforms
Client
PlatformFactory
+createWidget(): Widget
<<interface>>
Widget
+render()
create
Builder!
PdfReport
<<interface>>
ReportBuilder
+buildHeader() +buildReportLines() +buildTotal()
builder.buildHeader();
builder.buildReportLines();
builder.buildTotal();
Reporter
+createReport()
PdfReportBuilder
+buildHeader()+buildReportLines() +buildTotal()
create
Factory Method!
Client
+createAddress(type: String)
createAddress(String type) {
if(type == “Home”)
return new HomeAddress();
if(type == “Work”)
return new WorkAddress();
return null;
}
HomeAddress
create
<<interface>>
ClientAddress
WorkAddress
Singleton!
Environment
-instance: Environment -variables: EnvVariable[]
+getInstance(): Environment
+getVariables(): EnvVariable[]
Environment getInstance() {
if(instance == null)
instance = new Environment();
return instance;
}
- Don’t overuse (introduces global state)
- Consider concurrency issues with static
- Hard to test and reuse
Antipattern?
Structural Patterns!• Adapter!
Converts a class interface into another expected interface!
• Composite!Composes objects into tree structure to treat them uniformly!
• Decorator!Attaches new responsibilities to a class avoiding subclassing!
• Façade!Provides unified interface to a subsystem!
• Proxy!Provides a surrogate for an object to control access to it!!!
!
Adapter!
Adaptee
+adaptedOperation()
<<interface>>
Target
+operation()
Client
Adapter
-adaptee
+operation()
adaptee.adaptedOperation();
Composite!
Composite
-children: Component[]
+operation()
+add(Component)
+remove(Component) +getChild(index)
<<interface>>
Component
+operation()
Client
Leaf
+operation()
foreach(child in children)
child.opetation();
Decorator!
SearchDecorator
-content: CmsContent
+new(CmsContent) +render()
<<interface>>
CmsContent
+render()
TextContent
+render()
highlightFound(content);
content.render();
renderResourceLink();
- Extract Decorator interface
- Decorators can be nested
- Good alternative to inheritance
Façade!
Parser
Client
Compiler
+compile(source)
Scanner Code Generator
Compiler subsystem
Hides complex subsystem behind simple interface
Proxy!
Proxy
-realSubject: RealSubject
+request()
<<interface>>
Subject
+request()
RealSubject
+request()
realSubject.request();
Behavioral Patterns!• Chain of Responsibility!
Chain of objects passing the request until an object handles it!• Command!
Encapsulate the request in the object!
• Observer!A subject notifies observing objects about its state changes!
• Strategy!Encapsulate algorithms to make behavior changeable!
• Template Method!Defines the skeleton of an algorithm redefining steps in children !
• Visitor!Represents an operation to be performed on elements!!
!
Chain of Responsibility!
Handler
-successor: Handler
+handleRequest()
Client
ConcreteHandler1
+handleRequest()
ConcreteHandler2
+handleRequest()
if(canHandle()) {
doHandle();
} else {
sucessor.handleRequest();
}
Command!
Command
-receiver: Receiver
+execute() +new(Receiver)
Client
Command1
+execute()
Command2
+execute()
execute() {
receiver.action1();
}
Invoker
-commandQueue
+executeCommand()
Receiver
+action1() +action1()
execute() {
receiver.action2();
}
Observer!
ConcreteObserver1
+update()
ConcreteObserver2
+update()
<<interface>>
Observer
+update()
Subject
-observers: Observer[]
+attach(Observer) +detach(Observer)
+notify()
foreach(observer in observers)
observer.update();
Strategy!
NativeScrolling
+scroll()
SimulatedScrolling
+scroll()
<<interface>>
ScrollStrategy
+scroll()
Scrollable
-strategy: ScrollStrategy
+scroll()
strategy.scroll();
Good alternative to inheritance
Template Method!
ItemPrinter
#doInit() #doItemProcess(item)
ItemProcessor
-items
+templateMethod()
#doInit()
#doItemProcess(item)
templateMethod() {
PreInit();
doInit();
foreach(item in items)
doItemProcess(item);
}
Good practice to extend framework classes
doInit() {
printer = new Printer();
}
doItemProcess(item) {
printer.print(item);
}
Visitor!
<<interface>>
Visitor
+visit(Image) +visit(Text)
Client
PrintVisitor
+visit(Image) +visit(Text)
ResizeVisitor
+visit(Image) +visit(Text)
<<interface>>
Element
+accept(Visitor)
Image
+accept(Visitor)
Text
+accept(Visitor)
accept(visitor) {
visitor.visit(this); }
Allows to add new visitors not changing elements
Thank you!!
Your questions, please!!ARTEM TABALIN!
References!
• Frank Buschmann Pattern-Oriented Software Architecture!
• Craig Larman Applying UML and Patterns!
• Martin Fowler Patterns of Enterprise Application Architecture!
• Gang of Four Design Patterns!
• Gregor Hohpe, Bobby Woolf Enterprise Integration Patterns!
• Kent Beck Implementation Patterns!