在上一章节 Ruby 中的 Singleton 模块 ( 上 ) 中,我们有提到 Ruby 提供的 Singleton 模块可以很简单粗暴的帮我们快速实现单例模式。
因为篇幅限制,上一章节中还有一些知识点没有涉及到,本章节,我们就来理一理它们,包括以下两个知识点
- 继承和
instance
方法 clone
和dup
方法
继承和 instance
方法
在上一章节我们有提到,只要一个类 include Singleton
,那么它就自动成为单例类。也就自动获得了 instance
方法返回那个单例类
demo.rb
require 'singleton' class Demo include Singleton attr_accessor :title, :url end p Demo.instance
运行结果如下
[root@www.twle.cn ruby]# ruby demo.rb #<Demo:0x00007fcc4217f988>
其实,instance
方法是在 Singleton
模块中定义的,只不过当把这个模块加载到类 Demo
中时,Demo
类也拥有了这个方法。
这看起来工作正常对吧。
但,如果,嗯,我是说如果,一个类继承自 Demo
类,那又回发生什么呢?
呃哼,我们,我们写一个代码试一试
demo.rb
require 'singleton' class Demo include Singleton attr_accessor :title, :url end class Child < Demo; end rom = Child.instance rom.title = 'Ruby Object Model' rom.url = 'https://goo.gl/wq9eXv' demo = Demo.instance p demo p demo.title p demo.url
运行结果如下
[root@www.twle.cn ruby]# ruby demo.rb #<Demo:0x00007f95d69c2ed0> nil nil
虾米? 为什么什么都没有?
从代码中我们可以看到,我们为 Demo
类实现了单例模式。而 Child
类继承自 Demo
类,也自然就拥有 Demo
类的 instance
方法,而且这个方法也返回正常的单例。
问题就出在这个隐式的继承上面。从某些方面说,Child
类定义了它自己的 instance
方法,且不使用 Demo
类中定义的 instance
方法。这个新定义的 instance
方法返回的是 Child
类的实例,而不是 Demo
类的实例。
从某些方面说,这个逻辑很复杂,而且,是
include
方法导致的。
这种机制并不是一无是处,而是非常有用。这种机制允许 Child 类在处理独立的 Child 实例时继承 Singleton 模块和 Demo 类的行为。
因此,继承原则不会被破坏,而单例模式通过继承持久化。
这,看起来,是不是,很酷~~~~~~
但,我有一个疑问:从包含 Singleton 模块的类继承可能有用吗?
在回答之前,我们先来看一段代码
demo.rb
require 'singleton' class Client include Singleton attr_accessor :url, :port, :credentials end class DBClient < Client; end class ApiClient < Client; end db = DBClient.instance db.url = 'https://10.11.12.13' db.port = 4242 db.credentials = 'username:password' api = ApiClient.instance p api.url # => nil p api.port # => nil p api.credentials # => nil api.url = 'https://www.twle.cn' api.port = 8484 api.credentials = 'username:password' p api.url # => nil p api.port # => nil p api.credentials # => nil
运行结果如下
[root@www.twle.cn ruby]# ruby demo.rb nil nil nil "https://www.twle.cn" 8484 "username:password"
我们,是不是又打开了一扇奇妙之门。没想到单例模式的继承这么有用,哈哈。
clone
和 dup
方法
因为 Singleton
模块也定义了 clone
方法和 dup
方法,因此,当 Singleton 模块包含在类中时,Object#clone
和 Object#dup
方法被 Singleton 模块覆盖。
我们写一段代码来演示下
demo.rb
require 'singleton' class Demo include Singleton end test = Demo.instance p test.clone p test.dup p Test.clone
运行上面这段代码,输出结果如下
[root@www.twle.cn ruby]# ruby demo.rb /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/2.3.0/singleton.rb:100:in `clone': can't clone instance of singleton Demo (TypeError) from demo.rb:9:in `<main>'
实际上,Singleton
模块重新定义了这些方法以引发错误。
这是因为,单例模式,从本质上讲,不应该是可复制的