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