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 #no­op
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
<service­point id="CarBuilderService">
<invoke­factory>
<construct class="Car">
<service>DefaultCarImpl</service>
<service>DefaultEngineImpl</service>
</construct>
</invoke­factory>
</service­point>
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

Podobne dokumenty