Handout
Transkrypt
Handout
Obliczenia Symboliczne I
Zaawansowane techniki
programistyczne
property
class C(object):
def __init__(self, x):
self._x = x
def get_x(self):
return self._x
def set_x(self, x):
self._x = x
x = property(get_x, set_x)
obj = C(5)
obj.x = 6 # set
print obj.x # get
property
Pełne wywołanie:
property(fget=None, fset=None, fdel=None, doc=None)
Często sam getter:
property(fget)
property
class C(object):
def something1(self):
return whatever
something1 = property(something1)
@property
def something2(self):
return whatever Fabryki w pythonie
Klasa rozwiązań do zarządzania procesem tworzenia
obiektów:
W pythonie są wbudowane - klasy jako fabryki
Dwustopniowe tworzenie przez __new__
Niezależne fabryki – metody „ręczne”
Można podmieniać implementacje
Moduły jako fabryki
import posix as os
import nt as os
Inwersja kontroli (cdn...)
type.__call__
def __call__(cls,*a,**k):
nu = cls.__new__(cls,*a,**k)
if isinstance(nu, cls):
cls.__init__(nu,*a,**k)
return nu
#czesto:
def __new__(cls,...):
i=super(currentclass,cls).__new__(cls[, ...])
#modyfikujemy i return i Wrap/Hold Pattern
Dziedziczenie nie jest konieczne przy duck typing
Lepiej zastosować Object Composition w postaci:
Hold
Wrap
No chyba że korzystamy z Mixinów
Wrap/Hold Pattern
Hold:
O zawiera obiekt S który ma metody i pola
Wołamy O.S.method() albo O.S.pole
Nie powinno być więcej niż jeden „ . ” - bo łamie to
Prawo Demeter
Łamie enkapsulację
Wrap/Hold Pattern
Wrap := Hold + delegacja
Bezpośrednia
def method(self):
return self.S.method()
Automatyczna
def __getattr__(self,name):
return self.S.method()
Mocniejsze niż dziedziczenie
Wrap/Hold Pattern
class RestrictingWrapper(object):
def __init__(self, wrapee, block):
self._wrapee = wrapee
self._block = block
def __getattr__(self, n):
if n in self._block:
raise AttributeError, n
return getattr(self._wrapee, n)
Prawo Demeter
Prawo Demeter - Law of Demeter (LoD) nazywana także:
Zasadą minimalnej wiedzy - Principle of Least
Knowledge
Regułą ograniczania interakcji
Hollywood Principle
„Don't call us, we will call you”
Prawo Demeter
Metoda danego obiektu może odwoływać się jedynie do
metod należących do:
metod tego samego obiektu,
metod dowolnego parametru przekazanego do niej,
dowolnego obiektu przez nią stworzonego,
dowolnego składnika, klasy do której należy dana
metoda.
Mixin
Prosta klasa, bez hierarchii dodająca funkcjonalność
class C(object):
pass
class WithLog(object):
@property
def log(self):
...
class C_WithLog(C, WithLog):
pass
>>> c = C_WithLog()
>>> c.log.warn("hello")
Adapter
Typ a udostępnia protokół (interfejs) A
Ale my potrzebujemy interfejsu B
Co prawda A ma tą samą (albo większą
funkcjonalność) co B – ale inne wywołania (interfejs)
Tworzymy zatem Adapter – obiekt tłumaczący
wywołania z B na wywołania z A przez:
Wrap
Dziedziczenie
Mixin
Adapter
Potrzebny jest interfejs foobar(foo,bar) ale
mamy barfoo(bar,foo)
Tworzymy Adapter poprzez opakowanie:
Class FoobarWrapper(object):
def __init__(self,wrapee):
self.w=wrapee
def foobar(self,foo,bar):
return self.w.barfoo(bar,foo)
foobarer=FoobarWrapper(barfooer)
Adapter
Poprzez dziedziczenie:
Class Foobarer(Barfooer):
Def foobar(self,foo,bar):
Return self.barfoo(bar,foo)
foobarer=Foobarer(... to samo co barfooer)
... ale mamy problem, bo usztywniamy się
Adapter
Przez Mixin:
Class BF2FB:
Def foobar(self,foo,bar):
return self.barfoo(bar,foo)
Class Foobarer(BF2FB,Barfooer)#w locie
pass
foobarer=Foobarer(... to samo co barfooer)
Template Method
Wzorzec opisujący zachowanie klasy gdzie:
Główna logika jest w klasie abstrakcyjnej
Składa się metod „szablonów” i „handlerów”
Podklasy definiują handlery
Ponownie przykład: „Hollywood principle”
Template Method
class AbstractBase(object):
def orgMethod(self):
self.doThis()
self.doThat()
class Concrete(AbstractBase):
def doThis(self): ...
def doThat(self): ...
Template Method
class TheBase(object):
def doThis(self):
pass #noop
def doThat(self):
raise NotImplementedError
Template Method
W Pythonie można realizować implementacje w
oparciu o:
Bezpośrednią implementację
Introspekcję
Domyślny Protokół
Mixiny
Template Method
def__call__(self, result=None):
method = getattr(self, 'test'+ ... )
try: self.setUp()
except: result.addError(...)
try: method()
except self.failException, e:...
try: self.tearDown()
except: result.addError(...)
...result.addSuccess(...)..
Inwersja Kontroli
Użycie fabryki
Użycie „service locator pattern”
Zastosowanie „wstrzykiwania zależności”
(dependency injection)
Oraz:
ŻELAZNE STOSOWANIE SIĘ DO
PRAWA DEMETER
Inwersja Kontroli
Skutki
Nie tworzymy żadnych obiektów – wszystko tworzone jest
„gdzieś indziej” (w fabryce dostarczonej przez framework
IoC)
Nie ma zastosowania dla Singletonów, Flyweightów etc.
Wszystko odbywa się w frameworku IoC
Zalety:
Deklaratywne budowanie aplikacji !!!
Testowalność kodu dramatycznie wzrasta !
Minimalizacja powiązania między modułami („Coupling”)
Wady
Trudne tworzenie obiektów – czasem dodatkowa fabryka
staje się dependencją
Inwersja Kontroli
Skutki
Nie tworzymy żadnych obiektów – wszystko tworzone jest
„gdzieś indziej” (w fabryce dostarczonej przez framework
IoC)
Nie ma zastosowania dla Singletonów, Flyweightów etc.
Wszystko odbywa się w frameworku IoC
Zalety:
Deklaratywne budowanie aplikacji !!!
Testowalność kodu dramatycznie wzrasta !
Minimalizacja powiązania między modułami („Coupling”)
Wady
Trudne tworzenie obiektów – czasem dodatkowa fabryka
staje się dependencją
Frameworki IoC
Java:
Spring
Guice
Pico- i nano-container
Itd. itp.
Python
Python Spring
Snake-guice
???
Inwersja Kontroli - Interfejs
public interface ICar {
public float getSpeed();
public void setPedalPressure(final float PEDAL_PRESSURE);
}
public interface IEngine {
public float getEngineRotation();
public void setFuelConsumptionRate(final float FUEL_FLOW);
}
Inwersja Kontroli - brak
public class DefaultEngineImpl implements IEngine {
private float engineRotation = 0;
public float getEngineRotation() {
return engineRotation;
}
public void setFuelConsumptionRate(final float FUEL_FLOW) {
engineRotation = …;
}
}
Inwersja Kontroli - brak
public class DefaultCarImpl implements ICar {
private IEngine engine = new DefaultEngineImpl();
public float getSpeed() {
return engine.getEngineRotation()*…;
}
public void setPedalPressure(final float PEDAL_PRESSURE) {
engine.setFuelConsumptionRate(…);
}
}
Inwersja Kontroli - brak
public class MyApplication {
public static void main(String[] args) {
ICar car = new DefaultCarImpl();
car.setPedalPressure(5);
float speed = car.getSpeed();
System.out.println("Speed of the car is " + speed);
}
}
Inwersja Kontroli - brak
public class MyApplication {
public static void main(String[] args) {
ICar car = new DefaultCarImpl();
car.setPedalPressure(5);
float speed = car.getSpeed();
System.out.println("Speed of the car is " + speed);
}
}
Inwersja Kontroli - ręczna
public class DefaultCarImpl implements ICar {
private IEngine engine;
public DefaultCarImpl(final IEngine engineImpl) {
engine = engineImpl;
}
public float getSpeed() {
return engine.getEngineRotation()*?;
}
public void setPedalPressure(final float PEDAL_PRESSURE) {
engine.setFuelConsumptionRate(?);
}
}
Inwersja Kontroli - ręczna
public class CarFactory {
public static ICar buildCar() {
return new DefaultCarImpl(new DefaultEngineImpl());
}
}
public class MyApplication {
public static void main(String[] args) {
ICar car = CarFactory.buildCar();
car.setPedalPressure(5);
float speed = car.getSpeed();
System.out.println("Speed of the car is " + speed);
}
}
Inwersja Kontroli automatyczna
<servicepoint id="CarBuilderService">
<invokefactory>
<construct class="Car">
<service>DefaultCarImpl</service>
<service>DefaultEngineImpl</service>
</construct>
</invokefactory>
</servicepoint>
Inwersja Kontroli automatyczna
/** Implementation not shown **/
public class MyApplication {
public static void main(String[] args) {
Service service = (Service)DependencyManager.get("CarBuilderService");
ICar car = (ICar)service.getService(Car.class);
car.setPedalPressure(5);
float speed = car.getSpeed();
}
}
Inwersja Kontroli
from snakeguice import inject, Injected, Config
class MyLogger(object):
@inject(filename=Config('app.cfg:logger:filename'),
loglevel=Config('app.cfg:logger:loglevel'))
def __init__(self, filename,loglevel):
pass
Dependency Injection
Zależności można „wstrzykiwać” poprzez:
Konstruktory (constructor injection)
Metody dostępowe (setter injection)
Interfejs (interface injection)
public static void main(String argv) {
...
DependentClass dependency = GetCorrectDependency();
MainClass mainClass = new MainClass();
((IInjectDependent)mainClass).InjectDependent(dependency);
...
Don't Repeat Yourself
(DRY)
Zasada bazowa „nowych” frameworków
webowych
Ruby
Ruby on Rails. ...
Python
Django, Pylons, TurboGears ...
PHP
CakePHP, Symfony, ...
Groovy
Grails
Don't Repeat Yourself
(DRY)
Elementy wymagane:
Automatyzacja dużej części pracy (rake, bake,
manage.py ...)
Scaffolding – gotowa warstwa CRUD
DRY zastosowany do MVC
Model -> Object-Relational Mapping
View -> Dziedziczenie widoków
Controller -> Zarządzanie URLami i
delegacją
{% url app.views.viewfunc %}
Cool URI's don't change -> @permalink