Last active
March 21, 2020 14:15
-
-
Save Kcko/ee36cb59918c61b08e61805798fc55fd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
interface Entity | |
{ | |
public function accept(Visitor $visitor): string; | |
} | |
class Company implements Entity | |
{ | |
private $name; | |
/** | |
* @var Department[] | |
*/ | |
private $departments; | |
public function __construct(string $name, array $departments) | |
{ | |
$this->name = $name; | |
$this->departments = $departments; | |
} | |
public function getName(): string | |
{ | |
return $this->name; | |
} | |
public function getDepartments(): array | |
{ | |
return $this->departments; | |
} | |
// ... | |
public function accept(Visitor $visitor): string | |
{ | |
// See, the Company component must call the visitCompany method. The | |
// same principle applies to all components. | |
return $visitor->visitCompany($this); | |
} | |
} | |
class Department implements Entity | |
{ | |
private $name; | |
/** | |
* @var Employee[] | |
*/ | |
private $employees; | |
public function __construct(string $name, array $employees) | |
{ | |
$this->name = $name; | |
$this->employees = $employees; | |
} | |
public function getName(): string | |
{ | |
return $this->name; | |
} | |
public function getEmployees(): array | |
{ | |
return $this->employees; | |
} | |
public function getCost(): int | |
{ | |
$cost = 0; | |
foreach ($this->employees as $employee) { | |
$cost += $employee->getSalary(); | |
} | |
return $cost; | |
} | |
// ... | |
public function accept(Visitor $visitor): string | |
{ | |
return $visitor->visitDepartment($this); | |
} | |
} | |
class Employee implements Entity | |
{ | |
private $name; | |
private $position; | |
private $salary; | |
public function __construct(string $name, string $position, int $salary) | |
{ | |
$this->name = $name; | |
$this->position = $position; | |
$this->salary = $salary; | |
} | |
public function getName(): string | |
{ | |
return $this->name; | |
} | |
public function getPosition(): string | |
{ | |
return $this->position; | |
} | |
public function getSalary(): int | |
{ | |
return $this->salary; | |
} | |
// ... | |
public function accept(Visitor $visitor): string | |
{ | |
return $visitor->visitEmployee($this); | |
} | |
} | |
interface Visitor | |
{ | |
public function visitCompany(Company $company): string; | |
public function visitDepartment(Department $department): string; | |
public function visitEmployee(Employee $employee): string; | |
} | |
class SalaryReport implements Visitor | |
{ | |
public function visitCompany(Company $company): string | |
{ | |
$output = ""; | |
$total = 0; | |
foreach ($company->getDepartments() as $department) { | |
$total += $department->getCost(); | |
$output .= "\n--" . $this->visitDepartment($department); | |
} | |
$output = $company->getName() . | |
" (" . money_format("%i", $total) . ")\n" . $output; | |
return $output; | |
} | |
public function visitDepartment(Department $department): string | |
{ | |
$output = ""; | |
foreach ($department->getEmployees() as $employee) { | |
$output .= " " . $this->visitEmployee($employee); | |
} | |
$output = $department->getName() . | |
" (" . money_format("%i", $department->getCost()) . ")\n\n" . | |
$output; | |
return $output; | |
} | |
public function visitEmployee(Employee $employee): string | |
{ | |
return money_format("%#6n", $employee->getSalary()) . | |
" " . $employee->getName() . | |
" (" . $employee->getPosition() . ")\n"; | |
} | |
} | |
// USAGE | |
$mobileDev = new Department("Mobile Development", [ | |
new Employee("Albert Falmore", "designer", 100000), | |
new Employee("Ali Halabay", "programmer", 100000), | |
new Employee("Sarah Konor", "programmer", 90000), | |
new Employee("Monica Ronaldino", "QA engineer", 31000), | |
new Employee("James Smith", "QA engineer", 30000), | |
]); | |
$techSupport = new Department("Tech Support", [ | |
new Employee("Larry Ulbrecht", "supervisor", 70000), | |
new Employee("Elton Pale", "operator", 30000), | |
new Employee("Rajeet Kumar", "operator", 30000), | |
new Employee("John Burnovsky", "operator", 34000), | |
new Employee("Sergey Korolev", "operator", 35000), | |
]); | |
$company = new Company("SuperStarDevelopment", [$mobileDev, $techSupport]); | |
setlocale(LC_MONETARY, 'en_US'); | |
$report = new SalaryReport; | |
echo "Client: I can print a report for a whole company:\n\n"; | |
echo $company->accept($report); | |
echo "\nClient: ...or just for a single department:\n\n"; | |
echo $techSupport->accept($report); | |
/* | |
Client: I can print a report for a whole company: | |
SuperStarDevelopment (USD550,000.00) | |
--Mobile Development (USD351,000.00) | |
$100,000.00 Albert Falmore (designer) | |
$100,000.00 Ali Halabay (programmer) | |
$ 90,000.00 Sarah Konor (programmer) | |
$ 31,000.00 Monica Ronaldino (QA engineer) | |
$ 30,000.00 James Smith (QA engineer) | |
--Tech Support (USD199,000.00) | |
$ 70,000.00 Larry Ulbrecht (supervisor) | |
$ 30,000.00 Elton Pale (operator) | |
$ 30,000.00 Rajeet Kumar (operator) | |
$ 34,000.00 John Burnovsky (operator) | |
$ 35,000.00 Sergey Korolev (operator) | |
Client: ...or just for a single department: | |
Tech Support (USD199,000.00) | |
$ 70,000.00 Larry Ulbrecht (supervisor) | |
$ 30,000.00 Elton Pale (operator) | |
$ 30,000.00 Rajeet Kumar (operator) | |
$ 34,000.00 John Burnovsky (operator) | |
$ 35,000.00 Sergey Korolev (operator) | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
interface RoleVisitor | |
{ | |
public function visitUser(User $role); | |
public function visitGroup(Group $role); | |
} | |
interface Role | |
{ | |
public function accept(RoleVisitor $visitor); | |
} | |
class RecordingVisitor implements RoleVisitor | |
{ | |
/** | |
* @var Role[] | |
*/ | |
private array $visited = []; | |
public function visitGroup(Group $role) | |
{ | |
$this->visited[] = $role; | |
} | |
public function visitUser(User $role) | |
{ | |
$this->visited[] = $role; | |
} | |
/** | |
* @return Role[] | |
*/ | |
public function getVisited(): array | |
{ | |
return $this->visited; | |
} | |
} | |
class User implements Role | |
{ | |
private string $name; | |
public function __construct(string $name) | |
{ | |
$this->name = $name; | |
} | |
public function getName(): string | |
{ | |
return sprintf('User %s', $this->name); | |
} | |
public function accept(RoleVisitor $visitor) | |
{ | |
$visitor->visitUser($this); | |
} | |
} | |
class Group implements Role | |
{ | |
private string $name; | |
public function __construct(string $name) | |
{ | |
$this->name = $name; | |
} | |
public function getName(): string | |
{ | |
return sprintf('Group: %s', $this->name); | |
} | |
public function accept(RoleVisitor $visitor) | |
{ | |
$visitor->visitGroup($this); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
interface Visitable | |
{ | |
public function accept(Visitor $visitor); | |
} | |
interface Visitor | |
{ | |
public function visitUniversity(University $university): array; | |
public function visitStudent(Student $student): string; | |
} | |
class University implements Visitable | |
{ | |
private $name; | |
private $students; | |
public function __construct(string $name, array $students) | |
{ | |
$this->name = $name; | |
$this->students = $students; | |
} | |
public function getName(): string | |
{ | |
return $this->name; | |
} | |
public function getStudents(): array | |
{ | |
return $this->students; | |
} | |
public function accept(Visitor $visitor): array | |
{ | |
return $visitor->visitUniversity($this); | |
} | |
} | |
class Student implements Visitable | |
{ | |
private $name; | |
private $sickLeaves = []; | |
public function __construct(string $name) | |
{ | |
$this->name = $name; | |
} | |
public function addSickLeave(\DateTime $start, \DateTime $end) : void | |
{ | |
$this->sickLeaves[] = new SickLeave($start, $end); | |
} | |
public function getName(): string | |
{ | |
return $this->name; | |
} | |
public function getSickLeaves(): array | |
{ | |
return $this->sickLeaves; | |
} | |
public function accept(Visitor $visitor): string | |
{ | |
return $visitor->visitStudent($this); | |
} | |
} | |
class SickLeaveReport implements Visitor | |
{ | |
public function visitUniversity(University $university): array | |
{ | |
$msgs = []; | |
$msgs[] = "Generating sick leave report for: \"{$university->getName()}\""; | |
foreach ($university->getStudents() as $student) { | |
$msgs[] = $this->visitStudent($student); | |
} | |
return $msgs; | |
} | |
public function visitStudent(Student $student): string | |
{ | |
$daysMissed = 0; | |
foreach ($student->getSickLeaves() as $sickLeave) { | |
$daysMissed += $sickLeave->getStart()->diff($sickLeave->getEnd())->days + 1; | |
} | |
return "Student: {$student->getName()} missed {$daysMissed} days"; | |
} | |
} | |
class SickLeave | |
{ | |
private $start; | |
private $end; | |
public function __construct(\DateTime $start, \DateTime $end) | |
{ | |
$this->start = $start; | |
$this->end = $end; | |
} | |
public function getStart(): \DateTime | |
{ | |
return $this->start; | |
} | |
public function getEnd(): \DateTime | |
{ | |
return $this->end; | |
} | |
} | |
// USAGE | |
$john = new Student("John"); | |
$john->addSickLeave(new \DateTime("2019-10-01"), new \DateTime("2019-10-21")); | |
$john->addSickLeave(new \DateTime("2019-11-02"), new \DateTime("2019-11-10")); | |
$jan = new Student("Jan"); | |
$jan->addSickLeave(new \DateTime("2019-11-01"), new \DateTime("2019-11-15")); | |
$ann = new Student("Ann"); | |
$university = new University("Visitor University", [$john, $jan, $ann]); | |
$results = $university->accept(new SickLeaveReport()); | |
function show($data) | |
{ | |
foreach ($data as $datum) { | |
echo $datum.PHP_EOL; | |
} | |
} | |
show($results); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment