public function
Transkrypt
public function
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