中介者模式

正文:https://refactoringguru.cn/design-patterns/mediator

Go代码:https://refactoringguru.cn/design-patterns/mediator/go/example

module mediator_module

    implicit none
    private

    public :: station_manager_type, passenger_train_type, freight_train_type

    type, abstract :: train_type
    contains
        procedure(train_type_arrive), deferred :: arrive
        procedure(train_type_depart), deferred :: depart
        procedure(train_type_permit_arrival), deferred :: permit_arrival
    end type train_type

    type, abstract :: mediator_t
    contains
        procedure(mediator_type_can_arrive), deferred :: can_arrive
        procedure(mediator_type_notify_about_departure), deferred :: notify_about_departure
    end type mediator_t

    abstract interface

        subroutine train_type_arrive(self)
            import train_type
            class(train_type), intent(inout) :: self
        end subroutine train_type_arrive

        subroutine train_type_depart(self)
            import train_type
            class(train_type), intent(inout) :: self
        end subroutine train_type_depart

        subroutine train_type_permit_arrival(self)
            import train_type
            class(train_type), intent(inout) :: self
        end subroutine train_type_permit_arrival

        logical function mediator_type_can_arrive(self, train) result(can)
            import mediator_t, train_type
            class(mediator_t), intent(inout) :: self
            class(train_type), intent(in), target :: train
        end function mediator_type_can_arrive

        subroutine mediator_type_notify_about_departure(self)
            import mediator_t
            class(mediator_t), intent(inout) :: self
        end subroutine mediator_type_notify_about_departure

    end interface

    type, extends(train_type) :: passenger_train_type
        class(mediator_t), pointer :: mediator
    contains
        procedure :: arrive => passenger_train_type_arrive
        procedure :: depart => passenger_train_type_depart
        procedure :: permit_arrival => passenger_train_type_permit_arrival
    end type passenger_train_type

    type, extends(train_type) :: freight_train_type
        class(mediator_t), pointer :: mediator
    contains
        procedure :: arrive => freight_train_type_arrive
        procedure :: depart => freight_train_type_depart
        procedure :: permit_arrival => freight_train_type_permit_arrival
    end type freight_train_type

    type node_t
        class(train_type), pointer :: train
    end type node_t

    type, extends(mediator_t) :: station_manager_type
        logical :: is_platform_free = .true.
        type(node_t), allocatable :: list(:)
    contains
        procedure :: can_arrive => station_manager_type_can_arrive
        procedure :: notify_about_departure => station_manager_type_notify_about_departure
    end type station_manager_type

contains

    subroutine passenger_train_type_arrive(self)
        class(passenger_train_type), intent(inout) :: self
        if (.not. self%mediator%can_arrive(self)) then
            print *, "Passenger train: arrival blocked, waiting"
            return
        end if
        print *, "Passenger train: arrived"
    end subroutine passenger_train_type_arrive

    subroutine passenger_train_type_depart(self)
        class(passenger_train_type), intent(inout) :: self
        print *, "Passenger train: leaving"
        call self%mediator%notify_about_departure()
    end subroutine passenger_train_type_depart

    subroutine passenger_train_type_permit_arrival(self)
        class(passenger_train_type), intent(inout) :: self
        print *, "Passenger train: arrival permitted, arriving"
        call self%arrive()
    end subroutine passenger_train_type_permit_arrival

    subroutine freight_train_type_arrive(self)
        class(freight_train_type), intent(inout) :: self
        
        if (.not. self%mediator%can_arrive(self)) then
            print *, "Freight train: arrival blocked, waiting"
            return
        end if
        print *, "Freight train: arrived"
        
    end subroutine freight_train_type_arrive

    subroutine freight_train_type_depart(self)
        class(freight_train_type), intent(inout) :: self
        print *, "freight train: leaving"
        call self%mediator%notify_about_departure()
    end subroutine freight_train_type_depart

    subroutine freight_train_type_permit_arrival(self)
        class(freight_train_type), intent(inout) :: self
        print *, "Freight train: arrival permitted, arriving"
        call self%arrive()
    end subroutine freight_train_type_permit_arrival

    logical function station_manager_type_can_arrive(self, train) result(can)
        class(station_manager_type), intent(inout) :: self
        class(train_type), intent(in), target :: train
        
        if (self%is_platform_free) then
            self%is_platform_free = .false.
            can = .true.
            return
        end if
        self%list = [self%list, node_t(train)]
        can = .false.
        
    end function station_manager_type_can_arrive

    subroutine station_manager_type_notify_about_departure(self)
        class(station_manager_type), intent(inout) :: self
        class(train_type), pointer :: train
        
        if (.not. self%is_platform_free) then
            self%is_platform_free = .true.
        end if
        if (size(self%list) > 0) then
            train => self%list(1)%train
            !> 内存泄露
            self%list = self%list(2:)
            call train%permit_arrival()
        end if
        
    end subroutine station_manager_type_notify_about_departure

end module mediator_module
program mediator_main

    use mediator_module, only: station_manager_type,passenger_train_type,freight_train_type
    implicit none
    type(station_manager_type), target :: station_manager
    type(passenger_train_type) :: passenger_train
    type(freight_train_type) :: freight_train
    
    allocate(station_manager%list(0))
    passenger_train%mediator => station_manager
    freight_train%mediator => station_manager
    
    call passenger_train%arrive()
    call freight_train%arrive()
    call passenger_train%depart()
    
end program mediator_main

!> Results shall be:

!  Passenger train: arrived
!  Freight train: arrival blocked, waiting
!  Passenger train: leaving
!  Freight train: arrival permitted, arriving
!  Freight train: arrived