When we meet these requirements:
1) Controlling access to an object
2) providing a location-independent way of getting at the object
3) delaying its creation
all three actually have a common solution: the Proxy pattern.
Code First:
class BankAccount
attr_reader :balance
def initialize(starting_balance=0)
@balance = starting_balance
end
def deposit(amount)
@balance += amount
end
def withdraw(amount)
@balance -= amount
end
end
class BankAccountProxy
def initialize(real_object)
@real_object = real_object
end
def balance
@real_object.balance
end
def deposit(amount)
@real_object.deposit(amount)
end
def withdraw(amount)
@real_object.withdraw(amount)
end
end
the proxy object can treated as couterfeit object:
account = BankAccount.new(100)
account.deposit(50)
account.withdraw(10)
proxy = BankAccountProxy.new(account)
proxy.deposit(50)
proxy.withdraw(10)
The BankAccountProxy doesn't know much about the finance, he just send request to target object.
If we consider the access security issue, the folowing code will answer:
require 'etc'
class AccountProtectionProxy
def initialize(real_account, owner_name)
@subject = real_account
@owner_name = owner_name
end
def deposit(amount)
check_access
return @subject.deposit(amount)
end
def withdraw(amount)
check_access
return @subject.withdraw(amount)
end
def balance
check_access
return @subject.balance
end
def check_access
if Etc.getlogin != @owner_name
raise "Illegal access: #{Etc.getlogin} cannot access account."
end
end
end
The advantage of using a proxy for protection is that it gives us a nice separation of concerns: The proxy worries about who is or is not allowed to do what.
Protection proxies have another advantage over the naive “implement all of the security and functionality in one class” approach.
If we consider the remote proxy:
we can use the Ruby soap client for example:
require 'soap/wsdlDriver'
wsdl_url = 'http://www.webservicex.net/WeatherForecast.asmx?WSDL'
proxy = SOAP::WSDLDriverFactory.new( wsdl_url ).create_rpc_driver
weather_info = proxy.GetWeatherByZipCode('ZipCode'=>'19128')
Once the proxy object is set up, the client code no longer has to worry about the fact that the service actually lives at www.webservicex.net. Instead, it simply calls GetWeatherByZipCode and leaves all of the network details to the proxy.
If we consider the lazy creating issue:
class VirtualAccountProxy
def initialize(starting_balance=0)
@starting_balance=starting_balance
end
def deposit(amount)
s = subject
return s.deposit(amount)
end
def withdraw(amount)
s = subject
return s.withdraw(amount)
end
def balance
s = subject
return s.balance
end
def subject
@subject || (@subject = BankAccount.new(@starting_balance))
end
end
The lazy creating is really simple, we can create by proc passing from the contrusctor:
class VirtualAccountProxy
def initialize(&creation_block)
@creation_block = creation_block
end
# Other methods omitted ...
def subject
@subject || (@subject = @creation_block.call)
end
end
account = VirtualAccountProxy.new { BankAccount.new(10) }
The delegate by method_missing:
If you can sth.some_method if some_method is missing in sth instance, then it will climb up to its super classes to find it, if still not found, it will call the sth.method_missing, if sth.method_missing not found, it will call up to super classes till the Object class(Object has the method) it will raise a NoMethodError exception.
So we can eliminate the direct proxy method
class AccountProtectionProxy
def initialize(real_account, owner_name)
@subject = real_account
@owner_name = owner_name
end
def method_missing(name, *args)
check_access
@subject.send( name, *args )
end
def check_access
if Etc.getlogin != @owner_name
raise "Illegal access: #{Etc.getlogin} cannot access account."
end
end
end
class VirtualProxy
def initialize(&creation_block)
@creation_block = creation_block
end
def method_missing(name, *args)
s = subject
s.send( name, *args)
end
def subject
@subject = @creation_block.call unless @subject
@subject
end
end
分享到:
相关推荐
Addison.Wesley.Design.Patterns.in.Ruby.Dec.2007 高清PDF英文版
《Design Patterns in Ruby Dec 2007》是关于Ruby编程语言中设计模式的一份珍贵资料,这份2007年发布的PDF文档深入探讨了如何在Ruby语言中应用经典的设计模式。设计模式是软件工程中经过实践证明的有效解决方案模板...
design pattern in C# language
Design Patterns in Modern C++: Reusable Approaches for Object-Oriented Software Design English | PDF| 2018 | 312 Pages | ISBN : 1484236025Design Patterns in Modern C++: Reusable Approaches for Object...
Too often design patterns are explained using tricky concepts, when in fact they are easy to use and can enrich your everyday development. Design Patterns in ...
Learn how to implement design patterns in Java: each pattern in Java Design Patterns is a complete implementation and the output is generated using Eclipse, making the code accessible to all....
Alan Ezust在其著作《An Introduction to Design Patterns in C++ with Qt™, 2nd Edition》中探讨了设计模式的这一概念,并且在Qt框架的基础上讲解了如何在C++项目中应用这些设计模式。 C++是一种高性能、多范式的...
App Architecture: iOS Application Design Patterns in Swift 包含Source code 有钱请支持正版 没钱请默默学习 原书地址: https://www.objc.io/books/app-architecture 中文原书地址: ...
Data Structures And Algorithms With Object-oriented Design Patterns In Java.chm
Design Patterns in Java(2nd) 英文epub 第2版 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
and applications that run on various software and hardware platforms with little or no change in the underlying codebase, while still being a native application with native capabilities and speed....
Design Patterns in Modern C++ Reusable Approaches for Object-Oriented Software Design 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书
Pro Design Patterns in Swift 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者...