You are on page 1of 80

Wzorce projektowe

Architektura duych aplikacji w Pythonie

Marek Stpniowski http://stepniowski.com @mstepniowski

9000

Stages of a programmer

Chris Okasaki Purely Functional Data Structures Kent Beck Test-Driven Development Hunt, Thomas The Pragmatic Programmer Cormen, et al. Introduction to Algorithms Python

Level

Martin Fowler Patterns of Enterprise Application Architecture Abelson, Sussman Structure and Interpretation of Computer Programs

Gamma, et al. Design Patterns

My rst language 0

Time

Hunt, Thomas The Pragmatic Programmer Cormen, et al. Introduction to Algorithms

thon

Gamma, et al. Design Patterns

Wzorzec projektowy
def. Uniwersalne, sprawdzone w praktyce rozwizanie czsto pojawiajcych si, powtarzalnych problemw projektowych. Pokazuje powizania i zaleonoci pomidzy klasami oraz obiektami i uatwia tworzenie, modyfikacj oraz pielgnacj kodu rdowego.

Singleton

django.conf.settings

class Singleton { private static Singleton instance; private Singleton() {}; public static Singleton getInstance() { if (instance == null) instance = new Singleton(); return instance; }

class Singleton(object): _instance = None def __new__(cls, *args, **kw): if not cls._instance: cls._instance = ( super(Singleton, cls) .__new__(cls, *args, **kw)) return cls._instance

Alan Shallowey James R. Trott

Koncepcja procedury Kod rdowy Kod wynikowy Design patterns are higher-order abstractions for program organization. Peter Norvig

Marek Stpniowski

Abstract Factory Factory Method Builder Prototype Singleton Adapter Bridge Composite Decorator Facade Flyweight Proxy

Chain of Reponsibility Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor

23

DP

Adapter Bridge Composite Decorator Facade Flyweight Proxy Multiton Object Pool RAII Front Controller Null Object

Memento Observer State Strategy Template Method Visitor

32

Publish/Subscribe Blackboard Servant Specification

CC

Foreign Key Mapping Association Table Mapping Dependent Mapping Embedded Value Serialized LOB Single Table Inheritance Class Table Inheritance Concrete Table Inheritance Inheritance Mappers Metadata Mapping

Database Session State Gateway Mapper Layer Subtype Separated Interface Registry Value Object Money Special Case Plugin Service Stub Record Set

80

PoEAA

Embedded Value Serialized LOB Single Table Inheritance Class Table Inheritance Concrete Table Inheritance Inheritance Mappers Metadata Mapping Model Template View Model View Presenter Model View ViewModel

Separated Interface Registry Value Object Money Special Case Plugin Service Stub Record Set Layers KVO KVC

86

inne

Wzorce projektowe
Creational Architectural

Structural Behavioral Concurrency

Prototype Model View Controller Money

Smart Pointers? Procedures? Classes? Value Objects? Reference Counting? Closures? Asynchronous communication? Layers?

The first rule of Singletons is: you do not use Singletons The second rule of Singletons is: you do not use Singletons

django.conf.settings

class Borg: __shared_state = {} def __init__(self): self.__dict__ = self.__shared_state

class Singleton(type): def __init__(cls, name, bases, d): super(Singleton, cls).__init__( name, bases, d) cls._instance = None def __call__(cls, *args, **kw): if cls._instance is None: cls._instance = ( super(Singleton, cls) .__call__(*args, **kw)) return cls._instance class Settings(object): __metaclass__ = Singleton

# settings.py IM_A_CHARGIN_MAH_LAZER = True IM_A_FIRIN_MAH_LAZER = False tagline = '' # main.py import settings settings.tagline = 'Shoop da Whoop'

Multiton

logging
import logging log = logging.getLogger( 'setjam.classification.movie') log.warning( 'New ep of Bold & Beautiful!')

Wzorce projektowe
Invisible Formal Informal Peter Norvig

Singleton
Invisible Informal Formal

Multiton
Invisible Informal Formal

15/23

oryginalnych wzorcw projektowych niewidzialne lub uproszczone

First-class types: Abstract Factory, Factory Method, Flyweight, State, Proxy, Chain of Responsibility First-class functions: Command, Strategy, Template Method, Visitor Decorators: Mediator, Observer Modules: Singleton, Facade

+Iterator

)))))))))))))))))))))) )))))))))))))))))))))) )))))))))))))))))))))) )))))))))))))))))))))) )))))))))))))))))))))) ))))))))

Adapter Abstract Factory Method Factory Template Method Null Object Plugin Strategy Observer State

Hipo

tety

czna

firm

SeriesMatcher().match(data) ManualSeriesMatcher().match(data, pattern, trusted_keys) MovieMatcher().match(subscription, data)

Adapter
ClassicationEngine +match(4)

SeriesEngine +match(4)

ManualSeriesEngine +match(4)

MovieEngine +match(4)

SeriesMatcher +match(1)

ManualSeriesMatcher +match(4)

MovieMatcher +match(2)

class ClassificationEngine(object): pass class SeriesEngine(ClassificationEngine): def match(self, subscription, data, pattern, trusted_keys): return SeriesMatcher().match(data) class ManualSeriesEngine(ClassificationEngine): def match(self, subscription, data, pattern, trusted_keys): return ManualSeriesMatcher().match(data, pattern, trusted_keys) class MovieEngine(ClassificationEngine): def match(self, subscription, data, pattern, trusted_keys): return MovieMatcher().match(subscription, data)

class SeriesEngine(ClassificationEngine): def __init__(self): self.matcher = SeriesMatcher() def match(self, subscription, data, pattern, trusted_keys): return self.matcher.match(data) class ManualSeriesEngine(ClassificationEngine): def __init__(self): self.matcher = ManualSeriesMatcher() def match(self, subscription, data, pattern, trusted_keys): return self.matcher.match(data, pattern, trusted_keys) class MovieEngine(ClassificationEngine): def __init__(self): self.matcher = MovieMatcher() def match(self, subscription, data, pattern, trusted_keys): return self.matcher.match(subscription, data)

Factory

class ClassificationEngine(object): matcher_class = None def __init__(self, matcher=None): self.matcher = (matcher if matcher else self.matcher_class()) class SeriesEngine(ClassificationEngine): matcher_class = SeriesMatcher def match(self, subscription, data, pattern, trusted_keys): return self.matcher.match(data) class ManualSeriesEngine(ClassificationEngine): matcher_class = ManualSeriesMatcher def match(self, subscription, data, pattern, trusted_keys): return self.matcher.match(data, pattern, trusted_keys) class MovieEngine(object): matcher_class = MovieMatcher def match(self, subscription, data, pattern, trusted_keys): return self.matcher.match(subscription, data)

Nicer Series MatcherFactory Factory Fact

class ClassificationEngine(object): def __init__(self, matcher=None): self.matcher = self.get_matcher() class SeriesEngine(ClassificationEngine): def get_matcher(self): return SeriesMatcher() def match(self, subscription, data, pattern, trusted_keys): return self.matcher.match(data) class ManualSeriesEngine(ClassificationEngine): def get_matcher(self): return SeriesMatcher(defaults=settings.TRUSTED_KEYS) def match(self, subscription, data, pattern, trusted_keys): return self.matcher.match(data, pattern, trusted_keys) class MovieEngine(object): def get_matcher(self): return MovieMatcher() def match(self, subscription, data): return self.matcher.match(subscription, data)

Template Method

class ClassificationEngine(object): # ... def classify(self, subscription, subscription_data, data): preprocessed_data = self.preprocess(subscription, data) filtered_data = self.filter(subscription, preprocessed_data) matched_data = self.match(subscription, subscription_data, filtered_data)) classified_data = self.merge(subscription, matched_data) postprocessed_data = self.postprocess(subscription, classified_data) return postprocessed_data

class ClassificationEngine(object): # ... def classify(self, subscription, subscription_data, data, timer): with timer.label('preprocess'): preprocessed_data = self.preprocess(subscription, data) with timer.label('filter'): filtered_data = self.filter(subscription, preprocessed_data) with timer.label('match'): matched_data = self.match(subscription, subscription_data, filtered_data)) with timer.label('merge'): classified_data = self.merge(subscription, matched_data, extra_priorities) with timer.label('postprocess'): postprocessed_data = self.postprocess(subscription, classified_data) return postprocessed_data

Class-based generic views

Null Object
Client AbstractTimer +label(1) +dump(0)

Timer +label(1) +dump(0)

DummyTimer +label(1) +dump(0)

Do nothing

class Timer(object): def __init__(self, identifier=None): self.identifier, register = identifier, {} @contextmanager def label(self, label): t0 = time.time() yield t1 = time.time() self.register[label] = t1 - t0 def dump(self): r = dict(self.register) if self.identifier: r['_identifier'] = self.identifier return r class DummyTimer(Timer): def label(self, label): yield def dump(self): return {'_identifier': '<DummyTimer>'}

class ClassificationEngine(object): # ... def classify(self, subscription, subscription_data, data, timer=None): if timer is None: timer = DummyTimer() with timer.label('preprocess'): preprocessed_data = self.preprocess(subscription, data) with timer.label('filter'): filtered_data = self.filter(subscription, preprocessed_data) with timer.label('match'): matched_data = self.match(subscription, subscription_data, filtered_data)) with timer.label('merge'): classified_data = self.merge(subscription, matched_data, extra_priorities) with timer.label('postprocess'): postprocessed_data = self.postprocess(subscription, classified_data) return postprocessed_data

DisneyHarvester

AmazonHarvester HarvesterCommand +run(1) +runAll(0)

CrackleHarvester

NetixHarvester

ITunesHarvester

Plugin
def get_class(path): module_path, class_name = path.rsplit('.', 1) package_path = ([module_path.rsplit('.', 1)[0]] if '.' in module_path else None) module = __import__(module_path, fromlist=package_path) return getattr(module, class_name) # settings.py HARVESTERS = ( 'harvesters.disney_harvester.harvester.DisneyHarvester', 'harvesters.amazon_harvester.harvester.AmazonHarvester', 'harvesters.crackle_harvester.harvester.CrackleHarvester', 'harvesters.netflix_harvester.harvester.NetflixHarvester', 'harvesters.itunes_harvester.harvester.ITunesHarvester' )

admin.site.register(MyModel, MyModelAdmin)

def check_and_fixup_data(new_data, old_data, fixup_func=fixup_data, flagging_func=flag_data): is_worse, report = flagging_func(old_data, new_data) if is_worse: new_data = fixup_func(new_data, old_data) is_worse, report = flagging_func(old_data, new_data) return (is_worse, new_data, report)

Strategy

sorted(iterable)

sorted(iterable, cmp=None, key=None, reverse=False)

Observer
Observer +notify(*) Observable observerCollection +registerObserver(1) +unregisterObserver(1) +notifyObservers(*)

ObserverA +notify(*)

ObserverB +notify(*) notifyObservers(*) for observer in observerCollection: observer.notify(*)

django.core.signals django.db.models.signals

State

var Post = function (text, state) { this.initialize(text, state); }; _.extend(Post.prototype, { initialize: function (text, state) { this.text = text; this.state = state; }, getMaxCharacterCount: function () { this.state.getMaxCharacterCount(); }, getCharacterCount: function (text) { this.state.getCharacterCount(text); } });

var FacebookBehavior = function () {}; _.extend(FacebookBehavior.prototype, { getMaxCharacterCount: function () { return 450; }, getCharacterCount: function (text) { return text.length; } }); CH20 = 'xxxxxxxxxxxxxxxxxxxx'; var TwitterBehavior = function () {}; _.extend(TwitterBehavior.prototype, { getMaxCharacterCount: function () { return 140; }, getCharacterCount: function (text) { return text.replace(URL_REGEXP, CH20).length; } });

My God! Its full of patterns!

Patternitis

Architektura aplikacji

Wzorce projektowe

No silver bullet!

Wzorce projektowe

Wzorce projektowe + TDD

Wzorce projektowe + TDD


Michael Feathers, Working Effectively with Legacy Code

+ Seams

Wzorce projektowe + TDD


Michael Feathers, Working Effectively with Legacy Code

+ Seams

+ druga para oczu

Wzorce projektowe + TDD + Seams

Michael Feathers, Working Effectively with Legacy Code

+ druga para oczu + trzecia para oczu

I jako to idzie!

Marek Stpniowski http://stepniowski.com @mstepniowski

http://stepniowski.com/p/patterns

You might also like