Programowanie zorientowane obiektowo Mateusz Kołecki
Plan MVC Wstęp Separacja odpowiedzialnośći Antyprzykład Dobry przykład Wady/zalety MVC MVC to tylko początek - wzorce projektowe Dlaczego chcemy używać wzorców? Wzorzec Strategia - omówienie i przykład Inne wzorce Krótko o SOLID
HTTP/1.1 200 OK Content-Type: text/html Transfer-Encoding: chunked Dekoduję warstwa danych/logika biznesowa M Model żądanie HTTP Wybieram model warstwa prezentacji View V <html> <?php <?php <body> Wybieram Widok $response = $response; Controller </body> sterowanie C return aplikacją $this->render('profile.php', array( <?php </html> $user = $this->usersrepo ->getone(123); 'user' => $user GET /users/123 HTTP/1.1 )); Kontroler Model Widok
Separacja odpowiedzialności Kontroler Model Widok
Kontroler przyjmuje dane wejściowe od użytkownika reaguje na akcje użytkownika zarządza zmiany w modelu decyduje, który widok wyświetlić
Model logika biznesowa składowanie danych modyfikacja danych
Widok prezentacja danych z modelu
Antyprzykład <?php /* admin/panel.php */ $user = UsersTable::getInstance()->getOne( "SELECT * FROM users WHERE id={$_session['uid']" ); if (!$user!$user->isadmin) { header('location: /admin/logout?go=%2fadmin%2flogin'); exit;?> <html> <!--... --> <h1>admin panel</h1> <div class="admin-info">login: <?= $user->login?></div> <!--... --> </html>
Przykład (model) <?php /* lib/entities/userentity.php */ class UserEntity extends AbstractEntity { protected $login; protected $password; protected $isadmin; public static function create(array $data) { /*... */ public function getlogin() { /*... */ public function setlogin() { /*... */ public function checkpassword($password) { /*... */ public function setpassword($password, $salt = null) { /*... */ public function isadmin() { /*... */ public function setisadmin($bool) { /*... */
Przykład (model) cd. <?php /* lib/repositories/users.php */ class Users extends AbstractRepository implements UsersRepositoryInterface { /*... */ public function getone($id) { $user = $this->db->findone( 'SELECT * FROM users WHERE id=:id', array(':id' => (int)$id) ); if ($user === false) { return false; return UserEntity::create($user);
Przykład (widoki) <?php /* views/admin/panel.php */ $this->extend('layouts/admin.php');?> <div class="admin-info"> Login: <?= $this->user->login?> </div> <!--... --> <?php /* views/layouts/admin.php */?> <html> <!--... --> <body> <?= $this->content?> </body> </html>
Przykład (kontroler) <?php /* controllers/admincontroller.php */ class AdminController extends AbstractController { protected $usersrepo; protected $session; public function construct( UsersRepositoryInterface $usersrepo, SessionInterface $session, ) { $this->usersrepo = $usersrepo; $this->session = $session; /*... */
Przykład (kontroler) cd. <?php /* controllers/admincontroller.php */ class AdminController extends AbstractController { /*... */ public function indexaction() { $uid = $this->session->get('logged-in-user-id'); $user = $this->usersrepo->getone($uid); if (!$user $user->isadmin()) { $url = $this->url('/admin/logout', ['go' => '/admin/login']) return $this->redirect($url); return $this->render('admin/panel.php', array('user' => $user));
Antyprzykład <?php /* admin/panel.php */ $user = UsersTable::getInstance()->getOne( "SELECT * FROM users WHERE id={$_session['uid']" ); if (!$user!$user->isadmin) { header('location: /admin/logout?go=%2fadmin%2flogin'); exit;?> <html> <!--... --> <h1>admin panel</h1> <div class="admin-info">login: <?= $user->login?></div> <!--... --> </html>
Wady: większy poziom skomplikowania narzut kosztowne zmiany modelu pociągają za sobą zmiany widoków Korzyści: jasno podzielone odpowiedzialności łatwiejsze utrzymanie dużych projektów możliwość wymiany elementów aplikacji łatwiejsze testowanie elementów większa swoboda zarządzania pracą zespołu
Połowa za nami. Pytania?
Wzorce projektowe Dlaczego chcemy ich używać? Sprawdzone i uniwersalne rozwiązania powtarzających się problemów. Czym różnią się wzorce projektowe od frameworków? Wzorce są bardziej ogólne i abstrakcyjne. Bardziej nadają się do ponownego wykorzystania i są bardziej elastyczne.
Wzorce projektowe Czym nie są? implementacją
Przykład wzorca projektowego Strategia
Strategia Jedno zadanie a wymienne implementacje zadania Przykład: Różne strategie (algorytmy) służące do sortowania Różne strategie (mechanizmy) służące do keszowania
Strategia Kontekst «Interfejs» Strategia +zrobto() KonkretnaStrategiaA +zrobto() KonkretnaStrategiaB +zrobto()
Strategia DojazdDoPracy «Interfejs» StrategiaDojazdowa +dojedź() DojazdAutobusem +dojedź() DojazdRowerem +dojedź()
Strategia - przykład implementacji Różne metody keszowania danych z repozytorium
Strategia UsersCached +getone() «Interface» CacheInterface +get() +set() +delete() +clear() ArrayCache +get()... MemcachedCache +get()...
Strategia (interfejs strategii) <?php interface CacheInterface { public function set($key, $value, $ttl = null); public function get($key); public function delete($key); public function clear();
Strategia UsersCached +getone() «Interface» CacheInterface +get() +set() +delete() +clear() ArrayCache +get()... MemcachedCache +get()...
Strategia (implementacja strategii) <?php class ArrayCache implements CacheInterface { protected $data = array(); public function set($key, $value, $ttl = null) { // TODO: handle $ttl $this->data[$key] = $value; return true; public function delete($key) { /*... */ public function clear() { /*... */ public function get($key) { /*... */
Strategia UsersCached +getone() «Interface» CacheInterface +get() +set() +delete() +clear() ArrayCache +get()... MemcachedCache +get()...
Strategia (implementacja strategii 2) <?php class MemcachedCache implements CacheInterface { protected $memcached ; public function construct (Memcached $memcached ) { $this->memcahced = $memcached ; public function set($key, $value, $ttl = null) { $expires = $ttl === null? 0 : time() + $ttl; return $this->memcached->set($key, $value, $expires); public function get($key) { /*... */ public function delete($key) { /*... */ public function clear() { /*... */
Strategia UsersCached +getone() «Interface» CacheInterface +get() +set() +delete() +clear() ArrayCache +get()... MemcachedCache +get()...
Strategia (kontekst) <?php class UsersCached implements UsersRepositoryInterface { protected $usersrepo; protected $cache; public function construct( CacheInterface $cache, UsersRepositoryInterface $usersrepo ) { $this->cache = $cache; $this->usersrepo = $usersrepo; /*... */
Strategia (kontekst cd.) <?php class UsersCached implements UsersRepositoryInterface { /*... */ public function getone($id) { $cachekey = "users-repo-{$id"; $cacheduserdata = $this->cache->get($cachekey); if ($cacheduserdata) { return UserEntity::create($cachedUserData); $user = $this->usersrepo->getone($id); if ($user) { $this->cache->set($cachekey, $user->toarray(), 3600); return $user;
Strategia <?php $memcached = new Memcached(); $memcached->addserver('192.168.1.132', 11211); $memcachedcache = new MemcachedCache($memcached); $arraycache = new ArrayCache(); $usersrepo $memcachedrepo = new Users(); = new UsersCached($memcachedCache, $usersrepo); /* albo */ $arraycachedrepo = new UsersCached($arrayCache, $usersrepo);
Inne wzorce wzorce kreacyjne: Budowniczy Fabryka abstrakcyjna Metoda wytwórcza Prototyp Singleton wzorce strukturalne: Adapter Dekorator Fasada Kompozyt Most Pełnomocnik Pyłek wzorce czynnościowe (behawioralne): Interpreter Iterator Łańcuch zobowiązań Mediator Metoda szablonowa Obserwator Odwiedzający Pamiątka Polecenie Stan Strategia
SOLID
SOLID Single responsibility Zasada jednej odpowiedzialności Open-close Zasada otwarte-zamknięte Liskov substitution principle Zasada podstawienia Liskov Interface segregation principle Zasada separacji interfejsów Dependency inversion principle Zasada odwrócenia zależności