代理
代理物件通常用於確保對另一個物件的保護訪問,這個內部業務邏輯我們不希望汙染安全要求。
假設我們要保證只有特定許可權的使用者才能訪問資源。
代理定義:(確保只有實際可以看到預訂的使用者才能使用 consumer_service)
class Proxy
def initialize(current_user, reservation_service)
@current_user = current_user
@reservation_service = reservation_service
end
def highest_total_price_reservations(date_from, date_to, reservations_count)
if @current_user.can_see_reservations?
@reservation_service.highest_total_price_reservations(
date_from,
date_to,
reservations_count
)
else
[]
end
end
end
型號和預訂服務:
class Reservation
attr_reader :total_price, :date
def initialize(date, total_price)
@date = date
@total_price = total_price
end
end
class ReservationService
def highest_total_price_reservations(date_from, date_to, reservations_count)
# normally it would be read from database/external service
reservations = [
Reservation.new(Date.new(2014, 5, 15), 100),
Reservation.new(Date.new(2017, 5, 15), 10),
Reservation.new(Date.new(2017, 1, 15), 50)
]
filtered_reservations = reservations.select do |reservation|
reservation.date.between?(date_from, date_to)
end
filtered_reservations.take(reservations_count)
end
end
class User
attr_reader :name
def initialize(can_see_reservations, name)
@can_see_reservations = can_see_reservations
@name = name
end
def can_see_reservations?
@can_see_reservations
end
end
消費者服務:
class StatsService
def initialize(reservation_service)
@reservation_service = reservation_service
end
def year_top_100_reservations_average_total_price(year)
reservations = @reservation_service.highest_total_price_reservations(
Date.new(year, 1, 1),
Date.new(year, 12, 31),
100
)
if reservations.length > 0
sum = reservations.reduce(0) do |memo, reservation|
memo + reservation.total_price
end
sum / reservations.length
else
0
end
end
end
測試:
def test(user, year)
reservations_service = Proxy.new(user, ReservationService.new)
stats_service = StatsService.new(reservations_service)
average_price = stats_service.year_top_100_reservations_average_total_price(year)
puts "#{user.name} will see: #{average_price}"
end
test(User.new(true, "John the Admin"), 2017)
test(User.new(false, "Guest"), 2017)
優點
- 當訪問限制發生變化時,我們會避免在
ReservationService
中進行任何更改。 - 我們沒有將業務相關資料(
date_from
,date_to
,reservations_count
)與服務中的域無關概念(使用者許可權)混合在一起。 - 消費者(
StatsService
)也沒有許可權相關的邏輯
CAVEATS
- 代理介面始終與它隱藏的物件完全相同,因此使用代理包含的服務的使用者甚至不知道代理存在。