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