Top Banner
Выжить с ООП
67

Выжить с помощью ООП. Максим Гопей

Jan 06, 2017

Download

Software

EatDog
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Выжить с помощью ООП. Максим Гопей

Выжить с ООП

Page 2: Выжить с помощью ООП. Максим Гопей

Макс Гопей

Page 3: Выжить с помощью ООП. Максим Гопей
Page 4: Выжить с помощью ООП. Максим Гопей

Почему?

Page 5: Выжить с помощью ООП. Максим Гопей
Page 6: Выжить с помощью ООП. Максим Гопей
Page 7: Выжить с помощью ООП. Максим Гопей

Объектно-

Oриентированное

Программирование

7

Page 8: Выжить с помощью ООП. Максим Гопей

Почему ООП?

•   Это удобно

•   Это расширяемо

•   Адекватная модель мира

•   Позволяет строить асбтракции

•   Мне так сказали

8

Page 9: Выжить с помощью ООП. Максим Гопей

Объект олицетворяет объектв реальном мире.

9

Page 10: Выжить с помощью ООП. Максим Гопей

Объект олицетворяет объектв реальном мире вашем домене.

10

Page 11: Выжить с помощью ООП. Максим Гопей

Класс — это описание объекта

11

Page 12: Выжить с помощью ООП. Максим Гопей

Класс — это не область имен

12

Page 13: Выжить с помощью ООП. Максим Гопей

Пожалуйста, не делайте так:

use Spatie\Regex\Regex;

 

// Using `match`

Regex::match('/a/', 'abc'); // `MatchResult` object

Regex::match('/a/', 'abc')->hasMatch(); // true

Regex::match('/a/', 'abc')->result(); // 'a'

01.

02.

03.

04.

05.

06.

13

Page 14: Выжить с помощью ООП. Максим Гопей

Вместо:

Regex::match('/a/', 'abc'); // `MatchResult` objectRegex::match('/a/', 'abc')->hasMatch(); // trueRegex::match('/a/', 'abc')->result(); // 'a'

лучше:

$pattern = new Regex('/a/');$matchingResult = $pattern->match('abc'); // `MatchResult` object$matchingResult->hasMatch(); // true$matchingResult->result(); // 'a'

01.02.03.

01.02.03.04.

14

Page 15: Выжить с помощью ООП. Максим Гопей

Вместо:

Assertion::nullOrMax(null, 42); // successAssertion::nullOrMax(1, 42); // successAssertion::nullOrMax(1337, 42); // exception

лучше:

// since PHP 5.6Assertion\nullOrMax(null, 42); // successAssertion\nullOrMax(1, 42); // successAssertion\nullOrMax(1337, 42); // exception

01.02.03.

01.02.03.04.

15

Page 16: Выжить с помощью ООП. Максим Гопей

Инкапсуляция

16

Page 17: Выжить с помощью ООП. Максим Гопей

Реализация меняется

•   разные алгоритмы

•   разные хранилища

•   разные протоколы

17

Page 18: Выжить с помощью ООП. Максим Гопей

Абстракция не меняется

18

Page 19: Выжить с помощью ООП. Максим Гопей
Page 20: Выжить с помощью ООП. Максим Гопей

Наследование

20

Page 21: Выжить с помощью ООП. Максим Гопей
Page 22: Выжить с помощью ООП. Максим Гопей

Стакан

22

Page 23: Выжить с помощью ООП. Максим Гопей

Чашка

23

Page 24: Выжить с помощью ООП. Максим Гопей

Динозаврик с ручкой

24

Page 25: Выжить с помощью ООП. Максим Гопей
Page 26: Выжить с помощью ООП. Максим Гопей

Проектируйте для наследования.

Наследуйте, если спроектировали для этого.

26

Page 27: Выжить с помощью ООП. Максим Гопей

Полиморфизм

27

Page 28: Выжить с помощью ООП. Максим Гопей

Полиморфизм

Один интерфейс — множество реализаций.

И не важно, какая используется сейчас.

28

Page 29: Выжить с помощью ООП. Максим Гопей

interface Container {

public function drop();

}

class Glass implements Container {

public function drop() { /* well, crash */ }

}

class Cup implements Container {

public function drop() { /* well, crash, and throw the handle out */ }

}

class Cat {

public function dropContainer(Container $container) {

$container->drop();

}

}

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

13.

14.

29

Page 30: Выжить с помощью ООП. Максим Гопей

$cat = new Cat();

$cat->dropContainer(new Glass());

$cat->dropContainer(new Cup());

$cat->runAway();

01.

02.

03.

04.

30

Page 31: Выжить с помощью ООП. Максим Гопей

class ContainerCollection implements Iterator { public function current() : Container { /* ... */ }; // ...} $containersOnTable = new ContainerCollection(); // Your mom fills the collection here:$eventManager->dispatch('serve_table', $containers); array_walk($containersOnTable, function(Container $container) use ($cat) { $cat->dropContainer($container); });

01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.

31

Page 32: Выжить с помощью ООП. Максим Гопей

Инкапсуляция помогает скрыть реализацию за абстракицей.

Наследование помогает строить абстракции.

Полиморфизм помогает писать код на основе абстракций.

32

Page 33: Выжить с помощью ООП. Максим Гопей

33

Page 34: Выжить с помощью ООП. Максим Гопей

Методы классов

34

Page 35: Выжить с помощью ООП. Максим Гопей

class SearchEngine { public function indexProduct(Product $product) { $this->productIndex->add($product); $indexIsUpToDate = $this->productIndex->isUpToDate(); //.. }}

01.02.03.04.05.06.07.

35

Page 36: Выжить с помощью ООП. Максим Гопей

Три вида сообщений:

•   Команда

•   Запрос

•   Документ

36

Page 37: Выжить с помощью ООП. Максим Гопей

Метод-команда

•   принимает запрос на изменение состояния объекта,

•   ничего не возвращает (void),

•   выполняется успешно, либо бросает исключение.

37

Page 38: Выжить с помощью ООП. Максим Гопей

Метод-запрос

•   принимает запрос на получение информации,

•   возвращает значение указанного типа,

•   если это невозможно, возвращает NULL ,

•   или бросает исключение,

•   никогда не меняет наблюдаемое состояние объекта.

*

*

38

Page 39: Выжить с помощью ООП. Максим Гопей

Документ

•   результат работы метода-запроса.

39

Page 40: Выжить с помощью ООП. Максим Гопей

Принцип: Command Query Separation (CQS)

40

Page 41: Выжить с помощью ООП. Максим Гопей

Избегайте сеттеров

41

Page 42: Выжить с помощью ООП. Максим Гопей

class Person { private $firstName, $lastName, $gender, $email; // __constructor() // getters // setters} $person = new Person('Sheldon', 'Cooper', 'M', '[email protected]');render($person);

01.02.03.04.05.06.07.08.09.

42

Page 43: Выжить с помощью ООП. Максим Гопей
Page 44: Выжить с помощью ООП. Максим Гопей

class Person { private $firstName, $lastName, $gender, $email; // __constructor() // getters // setters} $person = new Person('Sheldon', 'Cooper', 'M', '[email protected]'); $person->setFirstName('Penny');$person->setGender('F'); render($person);

01.02.03.04.05.06.07.08.09.10.11.12.13.

44

Page 45: Выжить с помощью ООП. Максим Гопей
Page 46: Выжить с помощью ООП. Максим Гопей

Отдавайте предпочтениенеизменяемым объектам

(immutables)

46

Page 47: Выжить с помощью ООП. Максим Гопей

class Person { private $firstName, $lastName, $email, $gender;  public function rename(NameChangingRequest $request) { // change first/last/... names depending on request // throw exception if name is not male, for instance }  public function changeGender(GenderChangingRequest $request) { // A request which contains also the new name, // maybe the reason or whatever is needed. }} $person->changeGender(new GenderChangingRequest('M', 'New Name'));

01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.

47

Page 48: Выжить с помощью ООП. Максим Гопей

Метод — это транзакция

48

Page 49: Выжить с помощью ООП. Максим Гопей

class Product { public function reduceQuantity($deltaQuantity) { $this->quantity -= $deltaQuantity; } public function verifyStockAvailability() { if ($this->quantity == 0) { $this->removeFromStock(); } }} $product->reduceQuantity($orderedQuantity);$product->verifyStockAvailability();

01.02.03.04.05.06.07.08.09.10.11.12.13.

49

Page 50: Выжить с помощью ООП. Максим Гопей

class Product { private function reduceQuantity($deltaQuantity) { /*...*/ } private function verifyStockAvailability() { /*...*/ }  public function takeFromStock($quantity) { try { $this->reduceQuantity($orderedQuantity); $this->verifyStockAvailability(); } catch() { // ... } }} $product->takeFromStock($orderedQuantity);

01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.

50

Page 51: Выжить с помощью ООП. Максим Гопей

Название — это интерфейс

51

Page 52: Выжить с помощью ООП. Максим Гопей

function getProductUrl($product) {

return '/'

. str_replace(' ', '-', strtolower($product));

}

01.

02.

03.

04.

52

Page 53: Выжить с помощью ООП. Максим Гопей

$product = 'Ski Boots'; // product name

$product = 456; // product id

$product = [ // product data

'id' => 456,

'name' => 'Ski Boots'

];

01.

02.

03.

04.

05.

06.

53

Page 54: Выжить с помощью ООП. Максим Гопей

Name things by their real value

•   $product — object

•   $productName — string

•   $productId — integer / hash

•   $productData — array / structure

54

Page 55: Выжить с помощью ООП. Максим Гопей

Объекты-значения (value-objects)

55

Page 56: Выжить с помощью ООП. Максим Гопей

$person->addContactInformation(

new EmailAddress('[email protected]')

);

$person->addContactInformation(

new LinkedInProfileUrl('@max.gopey')

);

$this->redirect(new Url('https://stackoverflow.com'));

01.

02.

03.

04.

05.

06.

07.

56

Page 57: Выжить с помощью ООП. Максим Гопей

Объекты-значения не изменяются.

57

Page 58: Выжить с помощью ООП. Максим Гопей

Немного практики

58

Page 59: Выжить с помощью ООП. Максим Гопей

Интернет-аптека для ветеринаров.

Можно покупать товар:

•   для клиники (clinic),

•   для клиента (pet owner).

От этого зависит процесс заказа. Например, при заказе для

клиента можно оформить доставку в клинику или на дом.

59

Page 60: Выжить с помощью ООП. Максим Гопей

class Cgi_Nda_Model_Order_Mode

{

const ORDER_MODE_CLINIC = 1;

const ORDER_MODE_PET_OWNER = 2;

}

01.

02.

03.

04.

05.

60

Page 61: Выжить с помощью ООП. Максим Гопей

class Cgi_Nda_Model_Session

{

public function getOrderMode() : int {

return $this->getSessionValue('order_mode');

}

}

01.

02.

03.

04.

05.

06.

61

Page 62: Выжить с помощью ООП. Максим Гопей

class Cgi_Nda_Block_Order_Mode_Info{ public function getOrderMode () { $orderMode = $this->_getSession()->getOrderMode(); if ($orderMode) { if ($orderMode == Cgi_Nda_Model_Order_Mode::ORDER_MODE_PET_OWNER) { return 'For pet owner' ; } elseif ($orderMode == Cgi_Nda_Model_Order_Mode::ORDER_MODE_CLINIC) { return 'For clinic' ; } else { return false; } } else { return false; } } public function isSeparateShippingAddressAllowed () { $orderMode = $this->_getSession()->getOrderMode(); return $orderMode && $orderMode == Cgi_Nda_Model_Order_Mode::ORDER_MODE_PET_OWNER }}

01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.

62

Page 63: Выжить с помощью ООП. Максим Гопей

interface Cgi_Nda_Model_Order_Mode_Interface{ public function getCode() : int; public function getTitle() : string; public function isSeparateShippingAddressAllowed() : bool;}

01.02.03.04.05.06.07.08.

63

Page 64: Выжить с помощью ООП. Максим Гопей

class Cgi_Nda_Model_Order_Mode_Clinic implements Cgi_Nda_Model_Order_Mode_Interface{ public function getCode() : int { return 1; } public function getTitle() : string { return 'For Clinic'; } public function isSeparateShippingAddressAllowed() : bool { return false; }} class Cgi_Nda_Model_Order_Mode_PetOwner implements Cgi_Nda_Model_Order_Mode_Interface{ public function getCode() : int { return 2; } public function getTitle() : string { return 'For Pet Owner'; } public function isSeparateShippingAddressAllowed() : bool { return true; }}

01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.

64

Page 65: Выжить с помощью ООП. Максим Гопей

class Cgi_Nda_Model_Session

{

public function getOrderMode()

: Cgi_Nda_Model_Order_Mode_Interface {

return $this->getSessionValue('order_mode');

}

}

01.

02.

03.

04.

05.

06.

07.

65

Page 66: Выжить с помощью ООП. Максим Гопей

class Cgi_Nda_Block_Order_Mode_Info{ private $orderMode; public function __construct( Cgi_Nda_Model_Order_Mode_Interface $orderMode ) { $this->orderMode = $orderMode; } public function getOrderModeTitle() { return $this->orderMode->getTitle(); } public function isSeparateShippingAddressAllowed() { return $this->orderMode->isSeparateShippingAddressAllowed(); }}

01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.17.18.

66

Page 67: Выжить с помощью ООП. Максим Гопей