OOP Is More Than Cars and Dogs

641 views

Published on

When developers are introduced to object-oriented programming, one of the first things they are taught is that nouns turn into objects, verbs into methods, and Dog is a subclass of Animal. OOP is more than just turning things into classes and objects and showing that both Boats and Cars have motors, and that Dogs and Cats both speak(). Let's look at OOP in real-world settings and go beyond cars and dogs to see how to use object-oriented programming properly in PHP. Traits, composition, inheritance – none of it is off limits!

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
641
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
19
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

OOP Is More Than Cars and Dogs

  1. 1. OOP is More Than Cars and Dogs Chris Tankersley php[tek] 2015 php[tek] 2015 1
  2. 2. Who Am I • PHP Programmer for over 10 years • Work/know a lot of different languages, even COBOL • Primarily do Zend Framework 2 • https://github.com/dragonmantank php[tek] 2015 2
  3. 3. Quick Vocabulary Lesson • Class – Definition of code • Object – Instantiation of a Class • Member – Variable belonging to a class • Method – Function belonging to a class There will be more as we go along php[tek] 2015 3
  4. 4. php[tek] 2015 4 Class class Employee { protected $name; // This is a member protected $number; // This is a Method public function setData($data) { $this->name = $data['name']; $this->number = $data['number']; } public function viewData() { echo <<<ENDTEXT Name: {$this->name} Number: {$this->number} ENDTEXT; } }
  5. 5. Object <?php $manager= new Manager(); // ^ // | // `--- This is the Object php[tek] 2015 5
  6. 6. Why are we using OOP? php[tek] 2015 6
  7. 7. Let’s count the reasons • Because we’re told to, procedural programming leads to spaghetti code • We deal with objects every day, so it shouldn’t be too hard • We want to allow for code re-use • We want to group like code together • We want to easily extend our code • We want to be able to easily test our code php[tek] 2015 7
  8. 8. Getting OOP Right is Complicated php[tek] 2015 8
  9. 9. php[tek] 2015 9
  10. 10. php[tek] 2015 10
  11. 11. php[tek] 2015 11
  12. 12. php[tek] 2015 12
  13. 13. php[tek] 2015 13
  14. 14. php[tek] 2015 14
  15. 15. Can a Dog have Wheels? • Discuss (or listen to me talk some more) php[tek] 2015 15
  16. 16. Inheritance php[tek] 2015 16
  17. 17. What we’re all taught • Classes are “things” in the real world • We should construct class members based on Attributes • Number of wheels • Sound it makes • We should construct class methods based on “Actions” • Running • Speaking • Jumping php[tek] 2015 17
  18. 18. New Vocabulary • Parent Class – Class that is extended • Child Class – Class that is extending another class In PHP, a class can be both a Child and a Parent at the same time php[tek] 2015 18
  19. 19. Where I Learned It php[tek] 2015 19
  20. 20. Our Structure php[tek] 2015 20 Employee Manager Scientist Laborer
  21. 21. The Employee Class php[tek] 2015 21 abstract class Employee { protected $name; // Employee Name protected $number; // Employee Number public function setData($data) { $this->name = $data['name']; $this->number = $data['number']; } public function viewData() { echo <<<ENDTEXT Name: {$this->name} Number: {$this->number} ENDTEXT; } }
  22. 22. The Manager Class php[tek] 2015 22 class Manager extends Employee { protected $title; // Employee Title protected $dues; // Golf Dues public function setData($data) { parent::setData($data); $this->title = $data['title']; $this->dues = $data['dues']; } public function viewData() { parent::viewData(); echo <<<ENDTEXT Title: {$this->title} Golf Dues: {$this->dues} ENDTEXT; } }
  23. 23. The Scientist Class php[tek] 2015 23 class Scientist extends Employee { protected $pubs; // Number of Publications public function setData($data) { parent::setData($data); $this->pubs = $data['pubs']; } public function viewData() { parent::viewData(); echo <<<ENDTEXT Publications: {$this->pubs} ENDTEXT; } }
  24. 24. The Laborer Class php[tek] 2015 24 class Laborer extends Employee { }
  25. 25. What does this teach us? • Inheritance • Makes it easier to group code together and share it amongst classes • Allows us to extend code as needed • PHP allows Single inheritance php[tek] 2015 25
  26. 26. We use it all the time namespace ApplicationController; use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; Class IndexController extends AbstractActionController { public function indexAction() { /** @var VendorVendorService $vendor */ $vendor = $this->serviceLocator->get('VendorVendorService'); $view = new ViewModel(); return $view; } } php[tek] 2015 26
  27. 27. Why it Works (Most of the time, Kinda) • Allows us to extend things we didn’t necessarily create • Encourages code re-use • Allows developers to abstract away things php[tek] 2015 27
  28. 28. How to use it • Understand the difference between Public, Protected, and Private • Public – Anyone can use this, even children • Protected – Anything internal can use this, even children • Private – This is mine, hands off • Abstract vs Concrete Classes • Abstract classes cannot be instantiated directly, they must be extended php[tek] 2015 28
  29. 29. The Employee Class php[tek] 2015 29 abstract class Employee { protected $name; // Employee Name protected $number; // Employee Number public function setData($data) { $this->name = $data['name']; $this->number = $data['number']; } public function viewData() { echo <<<ENDTEXT Name: {$this->name} Number: {$this->number} ENDTEXT; } }
  30. 30. The Manager Class php[tek] 2015 30 class Manager extends Employee { protected $title; // Employee Title protected $dues; // Golf Dues public function setData($data) { parent::setData($data); $this->title = $data['title']; $this->dues = $data['dues']; } public function viewData() { parent::viewData(); echo <<<ENDTEXT Title: {$this->title} Golf Dues: {$this->dues} ENDTEXT; } }
  31. 31. An Example // Fatal error: Cannot instantiate abstract class Employee $employee = new Employee(); // We can do this though! $manager = new Manager(); // Fatal error: Cannot access protected property Manager::$name $manager->name = 'Bob McManager’; // setData is public, so we can use that $manager->setData(['name' => 'Bob McManager’,'number' => 1]); // We can also view the data, since it's public $manager->viewData(); php[tek] 2015 31
  32. 32. Why can Inheritance Be Bad • PHP only allows Single Inheritance on an Class • You can have a series of Inheritance though, for example CEO extends Manager, Manager extends Employee • Long inheritance chains can be a code smell • Private members and methods cannot be used by Child classes • Single Inheritance can make it hard to ‘bolt on’ new functionality between disparate classes php[tek] 2015 32
  33. 33. Composition over Inheritance php[tek] 2015 33
  34. 34. The General Idea • Classes contain other classes to do work and extend that way, instead of through Inheritance • Interfaces define “contracts” that objects will adhere to • Your classes implement interfaces to add needed functionality php[tek] 2015 34
  35. 35. Interfaces interface EmployeeInterface { protected $name; protected $number; public function getName(); public function setName($name); public function getNumber(); public function setNumber($number); } interface ManagerInterface { protected $golfHandicap; public function getHandicap(); public function setHandicap($handicap); } php[tek] 2015 35
  36. 36. Interface Implementation class Employee implements EmployeeInterface { public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } } class Manager implements EmployeeInterface, ManagerInterface { // defines the employee getters/setters as well public function getHandicap() { return $this->handicap; } public function setHandicap($handicap) { $this->handicap = $handicap; } } php[tek] 2015 36
  37. 37. This is Good and Bad • “HAS-A” is tends to be more flexible than “IS-A” • Somewhat easier to understand, since there isn’t a hierarchy you have to backtrack • Each class must provide their own Implementation, so can lead to code duplication php[tek] 2015 37
  38. 38. Traits • Allows small blocks of code to be defined that can be used by many classes • Useful when abstract classes/inheritance would be cumbersome • My Posts and Pages classes shouldn’t need to extend a Slugger class just to generate slugs. php[tek] 2015 38
  39. 39. Avoid Code-Duplication with Traits trait EmployeeTrait { public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } } class Employee implements EmployeeInterface { use EmployeeTrait; } class Manager implements EmployeeInterface, ManagerInterface { use EmployeeTrait; use ManagerTrait; } php[tek] 2015 39
  40. 40. Taking Advantage of OOP php[tek] 2015 40
  41. 41. Coupling php[tek] 2015 41
  42. 42. What is Coupling? • Coupling is how dependent your code is on another class • The more classes you are coupled to, the more changes affect your class php[tek] 2015 42
  43. 43. namespace ApplicationController; use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; class MapController extends AbstractActionController { public function indexAction() { // Position is an array with a Latitude and Longitude object $position = $this->getServiceLocator()->get('MapService’) ->getLatLong('123 Main Street', 'Defiance', 'OH'); echo $position->latitude->getPoint(); } } php[tek] 2015 43
  44. 44. Law of Demeter php[tek] 2015 44
  45. 45. Dependency Injection php[tek] 2015 45
  46. 46. What is Dependency Injection? • Injecting dependencies into classes, instead of having the class create it • Allows for much easier testing • Allows for a much easier time swapping out code • Reduces the coupling that happens between classes php[tek] 2015 46
  47. 47. Method Injection class MapService { public function getLatLong(GoogleMaps $map, $street, $city, $state) { return $map->getLatLong($street . ' ' . $city . ' ' . $state); } public function getAddress(GoogleMaps $map, $lat, $long) { return $map->getAddress($lat, $long); } } php[tek] 2015 47
  48. 48. Constructor Injection class MapService { protected $map; public function __construct(GoogleMaps $map) { $this->map = $map; } public function getLatLong($street, $city, $state) { return $this ->map ->getLatLong($street . ' ' . $city . ' ' . $state); } } php[tek] 2015 48
  49. 49. Setter Injection class MapService { protected $map; public function setMap(GoogleMaps $map) { $this->map = $map; } public function getMap() { return $this->map; } public function getLatLong($street, $city, $state) { return $this->getMap()->getLatLong($street . ' ' . $city . ' ' . $state); } } php[tek] 2015 49
  50. 50. Single Responsibility Principle php[tek] 2015 50
  51. 51. Single Responsibility Principle • Every class should have a single responsibility, and that responsibility should be encapsulated in that class php[tek] 2015 51
  52. 52. What is a Responsibility? • Responsibility is a “Reason To Change” – Robert C. Martin • By having more than one “Reason to Change”, code is harder to maintain and becomes coupled • Since the class is coupled to multiple responsibilities, it becomes harder for the class to adapt to any one responsibility php[tek] 2015 52
  53. 53. An Example /** * Create a new invoice instance. * * @param LaravelCashierContractsBillable $billable * @param object * @return void */ public function __construct(BillableContract $billable, $invoice) { $this->billable = $billable; $this->files = new Filesystem; $this->stripeInvoice = $invoice; } /** * Create an invoice download response. * * @param array $data * @param string $storagePath * @return SymfonyComponentHttpFoundationResponse */ public function download(array $data, $storagePath = null) { $filename = $this->getDownloadFilename($data['product']); $document = $this->writeInvoice($data, $storagePath); $response = new Response($this->files->get($document), 200, [ 'Content-Description' => 'File Transfer', 'Content-Disposition' => 'attachment; filename="'.$filename.'"', 'Content-Transfer-Encoding' => 'binary', 'Content-Type' => 'application/pdf', ]); $this->files->delete($document); return $response; } php[tek] 2015 53 https://github.com/laravel/cashier/blob/master/src/Laravel/Cashier/Invoice.php
  54. 54. Why is this Bad? • This single class has the following responsibilities: • Generating totals for the invoice (including discounts/coupons) • Generating an HTML View of the invoice (Invoice::view()) • Generating a PDF download of the invoice(Invoice::download()) • This is coupled to a shell script as well • Two different displays handled by the class. Adding more means more responsibility • Coupled to a specific HTML template, the filesystem, the Laravel Views system, and PhantomJS via the shell script php[tek] 2015 54
  55. 55. How to Improve • Change responsibility to just building the invoice data • Move the ‘output’ stuff to other classes php[tek] 2015 55
  56. 56. Unit Testing php[tek] 2015 56
  57. 57. [Could not afford licensing fee for Grumpy Testing Picture] php[tek] 2015 57
  58. 58. This is not a testing talk • Using Interfaces makes it easier to mock objects • Reducing coupling and following Demeter’s Law makes you have to mock less objects • Dependency Injection means you only mock what you need for that test • Single Responsibility means your test should be short and sweet • Easier testing leads to more testing php[tek] 2015 58
  59. 59. Final Thoughts php[tek] 2015 59
  60. 60. We can make a dog with wheels! • Abstract class for Animal • Class for Dog that extends Animal • Trait for Wheels • With the write methodology, we could even unit test this In the real world, we can now represent a crippled dog php[tek] 2015 60
  61. 61. Here’s a cute dog instead php[tek] 2015 61
  62. 62. Thank You! http://ctankersley.com chris@ctankersley.com @dragonmantank https://joind.in/13731 php[tek] 2015 62
  63. 63. Photos • Slide 9 - http://bit.ly/1dkaoxS • Slide 10 - http://bit.ly/1c4Gc8z • Slide 11 - http://bit.ly/1R3isBp • Slide 12 - http://bit.ly/1ScEWRZ • Slide 13 - http://bit.ly/1Bc0qUv • Slide 14 - http://bit.ly/1ILhfNV php[tek] 2015 63

×