Ruby 中的 Singleton 模块 ( 下 )

yufei       1 月 前       36

在上一章节 Ruby 中的 Singleton 模块 ( 上 ) 中,我们有提到 Ruby 提供的 Singleton 模块可以很简单粗暴的帮我们快速实现单例模式。

因为篇幅限制,上一章节中还有一些知识点没有涉及到,本章节,我们就来理一理它们,包括以下两个知识点

  1. 继承和 instance 方法
  2. clonedup 方法

继承和 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"

我们,是不是又打开了一扇奇妙之门。没想到单例模式的继承这么有用,哈哈。

clonedup 方法

因为 Singleton 模块也定义了 clone 方法和 dup 方法,因此,当 Singleton 模块包含在类中时,Object#cloneObject#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 模块重新定义了这些方法以引发错误。

这是因为,单例模式,从本质上讲,不应该是可复制的

目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2018 简单教程 twle.cn All Rights Reserved.