现在的位置: 首页 > 综合 > 正文

从自己实现Ruby单例模式揭秘Ruby模块内幕

2013年10月10日 ⁄ 综合 ⁄ 共 2955字 ⁄ 字号 评论关闭

     从自己实现Ruby单例模式揭秘Ruby模块内幕

缘起

整个故事要从某一天开始说起,那天,我看到一篇文章介绍了Ruby中实现单例模式的模块。Singleton模块,只要include  Singleton模块,就可以为一个Ruby类添加单例功能。

我颇为惊奇,于是查看Singleton.rb源码,洋洋洒洒几百行,看不懂。做技术的都知道,遇到不理解的东西我们总是想探究清楚,否则必茶不思饭不想,夜不能寐。

于是,我就想到CSDN论坛问问Ruby高人,不料Ruby论坛总是系统维护中这个状态,想到其他Ruby社区问问,但一想还是算了。我平常都不逛其他社区的。

于是,继续钻研,费了一晚上的时间,终有所获。虽然没有完全看懂Ruby核心库中的Singleton模块的源码,但自己也鼓捣出了一个Singleton模块出来。

并且对Ruby模块和Ruby语言的本质有了更深的认识。

 

 

 

使用模块类载入方法实现的单例模块!

源代码:

下面请大家直接看看我的简单版的Singleton模块的源代码。

 

    单例模块,存在的意义就是在模块被载入类时,给类添加类方法和创建对象实例等

module   Singleton

这个方法在模块被载入类时调用,传入的参数是  类对象

def self.included(base)  

这个操作把另一个模块直接添加到Class对象上。类对象上的方法就是类方法。

尽管模块中的方法是模块的实例方法。

    base.extend(SingletonClass);

     

        puts("Singleton  Include!");

创建类的实例,然后把类的new方法设为私有类方法,防止被调用

最后把类的实例存放到类的方法中。

        myInstance=base.new();

   base.private_class_method :new

      # private_class_method :new

    base.setClass(myInstance);

      

      

       #createSingleton(base);

      

      

 

     end

   

      

       end

    

   module  SingletonClass

这个模块附加上去的类方法,把类实例保存在模块的实例变量中。也就是目标类的类变量中。

    def setClass(base)

        puts("setClass");

        @myClass=base;

       

        return  @myClass;

      end

     单例方法,仅仅返回类的保护实例变量。

       def instance()

        puts("instance");

      

       

        return  @myClass;

      end

 

  end

 

 

 

class Test

   include Singleton;

 #private_class_method :new

     

  def say(val)

      puts(val);

    end

 

end

 

test=Test.instance();

test.say("sssssss");

#test=Test.new();  # fail

 

 

技术详解

上面展示的Singleton模块的源代码,虽然代码量不多,却使用了很多Ruby的高级技术。很有教学意义。当然,如果直接拿去使用也没有问题,虽然没有官方的Singleton模块功能强,却一样实现了单例模式。

 

通过模块怎样给类添加类方法

Singleton模块的功能是,目标类通过

include Singleton;

这一行代码,可以给自己的类添加一个类方法instance().

我们一般使用Module,是给Module定义一些实例方法,然后这些方法就会成为目标类的实例方法。

我们也可以给Module定义类方法。这些方法必须要通过

Module.方法名()调用。

试验下来,我们发现,目标类上不能调用模块的方法。

 

那怎么才能实现通过Module给目标类添加类方法呢?

 

我们知道,Ruby中类是类,但其实类也是一个对象,一个特殊的对象。

Ruby的类对象就是Class类的实例。因此,对象具有的所有特征,类对象也都有。

JavaJSC#都是如此的。

 

Ruby的类对象上的实例方法,不就是类的方法吗?

鉴于此,我们想到,只要在类对象上添加实例方法,那么我们就可以给类添加类方法。

 

RubyJavaScript一样,都可以给对象而不是类型动态添加方法。这样就成了。

 

Ruby的类继承体系

           ObjectClass

         ……

      BaseClass

          ^

          |

(SingletonClass)

         ^

         |     各个includeModule

       SomeClass

         ^    

         |

     (SingletonClass)

         ^

         |

     someObj

 

 

上面就是Ruby的继承体系,独特而又精妙。

Ruby可以实现动态增删对象的成员,而不仅仅是动态增删类的成员。

另一种具备此种神功的就是JavaScript。但是,Ruby内部实现这些强大功能的内部机制和JavaScript的机制是截然不同的。

可谓殊途同归!

 

 

1,Ruby是单根结构的单继承体系的语言,它的根基类是Object类。所有的类最后都继承Object类,这和其他语言一样。JavaC#JavaScriptSmallTalk等都是如此。

 

2Ruby的类可以包括多个模块。通过

include ModuleName

   即可达到此种目的,这种技术叫做混入Mixin

   通过这种技术,使单继承的Ruby达到了多继承的效果。

    JavaScript也可以实现混入Mixin技术。这个我以后有时间再说。

 

在方法查找时,是先查找类本身定义的方法,然后再查找引入的模块中的方法。最后查找基类的方法。

 

3Ruby不仅可以使用反射技术实现动态增删类型的成员,还可以动态增删对象的成员。

也就是说,Ruby类的各个实例,可以在运行时具备完全不同的数据结构和方法、行为特征!

这种强大的特性,JavaScript也具备。

现在让我们看看Ruby是怎样做到这一点的。

Ruby的每一个类实例,都有一个单独的特殊的类型,SingletonClass

    (SingletonClass)

         ^

         |

     someObj

 

注意,SingletonClass不是Singleton模块,不是用于实现单例模式的那个冬冬。

Ruby的一个特殊特征就是,一切都是类。JavaScript的哲学是一切都是对象。

既然任何对象都从属于一个唯一的类型,那么我们只要使用动态修改Ruby类的成员的技术修改这个SingletonClass的成员,就可以实现动态修改单个对象的成员了。

 

4,回到上面的Singleton模块的例子,为什么我们要讲Ruby动态修改单个对象的方法呢?因为我们要使用这种技术实现给Ruby

抱歉!评论已关闭.