Wzorce projektowe - architektura dużych aplikacji w Pythonie

Post on 25-Apr-2015

821 views 0 download

description

Autor: Marek Stępniowskihttp://stepniowski.com/

Transcript of Wzorce projektowe - architektura dużych aplikacji w Pythonie

Wzorce projektoweArchitektura dużych aplikacji w Pythonie

Marek Stępniowskihttp://stepniowski.com

@mstepniowski

Gamma, et al.Design Patterns

Time

Hunt, ThomasThe PragmaticProgrammer Martin Fowler

Patterns of Enterprise Application Architecture

Cormen, et al.Introduction to

Algorithms

Kent BeckTest-Driven

Development

Python

Abelson, SussmanStructure and

Interpretation of Computer Programs

Chris OkasakiPurely Functional Data Structures

My first language

Stages of a programmer

Level

9000

0

Gamma, et al.Design Patterns

Time

Hunt, ThomasThe PragmaticProgrammer Martin Fowler

Patterns of Enterprise Application Architecture

Cormen, et al.Introduction to

Algorithms

Kent BeckTest-Driven

Development

Python

Abelson, SussmanStructure and

Interpretation of Computer Programs

Chris OkasakiPurely Functional Data Structures

My first language

Stages of a programmer

Level

9000

0

Wzorzec projektowy

def. Uniwersalne, sprawdzone w praktyce rozwiązanie często pojawiających się, powtarzalnych problemów projektowych. Pokazuje powiązania i zależoności pomiędzy klasami oraz obiektami i ułatwia tworzenie, modyfikację oraz pielęgnację kodu źródłowego.

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 ShalloweyJames R. Trott

Design patterns are higher-order abstractions for program organization.

Peter Norvig

Kod wynikowy

Kod źródłowy

Koncepcja procedury

Marek Stępniowski

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

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

32

Multiton

Object Pool

RAII

Front Controller

Null Object

Publish/Subscribe

Blackboard

Servant

Specification

CC

80

Transaction Script

Domain Model

Table Module

Service Layer

Table Data Gateway

Row Data Gateway

Active Record

Data Mapper

Unit of Work

Identity Map

Lazy Load

Identity Field

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

Query Object Repository

Model View Controller

Page Controller

Front Controller

Template View

Transform View

Two-Step View

Application Controller

Remote Facade

Data Transfer Object

Client Session State

Server Session State

Database Session State

Gateway

Mapper

Layer Subtype

Separated Interface

Registry

Value Object

Money

Special Case

Plugin

Service Stub

Record Set PoEAA

86

Transaction Script

Domain Model

Table Module

Service Layer

Table Data Gateway

Row Data Gateway

Active Record

Data Mapper

Unit of Work

Identity Map

Lazy Load

Identity Field

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

Query Object Repository

Model View Controller

Page Controller

Front Controller

Template View

Transform View

Two-Step View

Application Controller

Remote Facade

Data Transfer Object

Client Session State

Server Session State

Database Session State

Gateway

Mapper

Layer Subtype

Separated Interface

Registry

Value Object

Money

Special Case

Plugin

Service Stub

Record Set

Model Template View

Model View Presenter

Model View ViewModel

Layers

KVO

KVC inne

Wzorce projektowe

Behavioral

Structural

Creational Architectural

Concurrency

Money

Model View Controller

Prototype

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 = TrueIM_A_FIRIN_MAH_LAZER = False

tagline = ''

# main.pyimport settings

settings.tagline = 'Shoop da Whoop'

Multiton

import logging

log = logging.getLogger( 'setjam.classification.movie')

log.warning( 'New ep of Bold & Beautiful!')

logging

Wzorce projektowe

Formal

Informal

Invisible

Peter Norvig

Singleton

Invisible

Informal

Formal

Multiton

Invisible

Informal

Formal

oryginalnych wzorców projektowychniewidzialne lub uproszczone15/23

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

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

AdapterAbstract FactoryMethod FactoryTemplate MethodNull ObjectPluginStrategyObserverState

9

Hipotetyczna firma

SeriesMatcher().match(data)

ManualSeriesMatcher().match(data, pattern, trusted_keys)

MovieMatcher().match(subscription, data)

+match(4)ClassificationEngine

+match(4)SeriesEngine

+match(4)ManualSeriesEngine

+match(4)MovieEngine

+match(1)SeriesMatcher

+match(4)ManualSeriesMatcher

+match(2)MovieMatcher

Adapter

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)

MatcherFactorySeries FactoryNicer Factory

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

+label(1)+dump(0)

AbstractTimer

+label(1)+dump(0)

Timer+label(1)+dump(0)

DummyTimer

Client

Do nothing

Null Object

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

+run(1)+runAll(0)

HarvesterCommand

DisneyHarvester

AmazonHarvester

CrackleHarvester

NetflixHarvester

ITunesHarvester

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.pyHARVESTERS = ( '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')

Plugin

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)

+notify(*)Observer

+notify(*)ObserverA

+notify(*)ObserverB

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

+registerObserver(1)+unregisterObserver(1)+notifyObservers(*)

observerCollectionObservable

Observer

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! It’s full of patterns!

A B

A B

A BC

A BC

A BC

Patternitis

Architektura aplikacji

Wzorce projektowe

No silver bullet!

Wzorce projektowe

Wzorce projektowe

+ TDD

Wzorce projektowe

+ TDD

+ Seams Michael Feathers,

Working Effectively with Legacy Code

Wzorce projektowe

+ TDD

+ Seams Michael Feathers,

Working Effectively with Legacy Code

+ 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 Stępniowskihttp://stepniowski.com

@mstepniowski