Visitor

7/23/2021 OOPPatternBehavioral pattern

# Description

Tách behavior ra khỏi object, từ đó có thể thêm behavior mới vào hệ thống mà không làm thay đổi code hiện tại

# Example

Quản lí các role: administrator và member. administrator thì có thể xem thông tin của member, còn member thì chỉ có thể xem thông tin của mình.

  • Abstract class hoặc interface cho Role và Visitor:

    Role: declare method to accept vào visitor

    interface Role
    {
        public function accept(Visitor $visitor);
    }
    
    1
    2
    3
    4

    Visitor: declare các behavior cho từng loại Role

    interface Visitor
    {
        public function visitAdministrator(Administrator $administrator);
    
        public function visitMember(Member $member);
    }
    
    1
    2
    3
    4
    5
    6
  • Class Administrator và Member chỉ declare cấu trúc của class, behavior accept được tách ra xử lí ở những class implement Visitor

    class Administrator implements Role
    {
        private int $id;
        private array $members;
    
        public function __construct($id, $members)
        {
            $this->id = $id;
            $this->members = $members;
        }
    
        public function getId()
        {
            return $this->id;
        }
    
        public function getMembers()
        {
            return $this->members;
        }
    
        public function accept(Visitor $visitor)
        {
            return $visitor->visitAdministrator($this);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class Member implements Role
    {
        private int $id;
        private string $name;
    
        public function __construct($id, $name)
        {
            $this->id = $id;
            $this->name = $name;
        }
    
        public function getId()
        {
            return $this->id;
        }
    
        public function getName()
        {
            return $this->name;
        }
    
        public function accept(Visitor $visitor)
        {
            return $visitor->visitMember($this);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
  • ViewInfoVisitor: Class xử lí xem thông tin cho từng loại role.

    class ViewInfoVisitor implements Visitor
    {
        public function visitAdministrator(Administrator $administrator)
        {
            echo "Administrator: Id : {$administrator->getId()} <br>";
            foreach ($administrator->getMembers() as $member) {
                $this->visitMember($member);
            }
        }
    
        public function visitMember(Member $member)
        {
            echo "Member: ID : {$member->getId()}, Name: {$member->getName()} <br>";
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
  • CountMemberVisitor: Xử lí đếm member.

    class CountMemberVisitor implements Visitor
    {
        public function visitAdministrator(Administrator $administrator)
        {
            $qty = count($administrator->getMembers());
            echo "Member qty: {$qty} <br>";
        }
    
        public function visitMember(Member $member)
        {
            echo "You are not an administrator <br>";
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

→ Như vậy đã tách được logic của behavior ra khỏi các class Administrator hay Member. Nếu có thêm hay thay thế các behavior thì cũng không cần update lại code của các class đó.

$member1 = new Member(1, "member A");
$member2 = new Member(2, "member B");

$administrator = new Administrator(1, [$member1, $member2]);

$member1->accept(new ViewInfoVisitor());
$member1->accept(new CountMemberVisitor());
// output:
    /*
    Member: ID : 1, Name: member A
    You are not an administrator
    */

$administrator->accept(new ViewInfoVisitor());
$administrator->accept(new CountMemberVisitor());
// output:
    /*
    Administrator: Id : 1
    Member: ID : 1, Name: member A
    Member: ID : 2, Name: member B
    Member qty: 2
    */

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23