English 中文(简体)
OCaml中的经典单例实现
原标题:
  • 时间:2009-02-11 04:55:13
  •  标签:

我试图在OCaml中概念化Singleton设计模式(作为Java的代表),看到每个实例都暗示了函数器或模块,但我在GoF的概念验证中没有使用其中任何一个。基本上,我想使用OCaml重新创建以下功能:

public class Singleton
{
 private static Singleton UniqueInstance; 
 private Singleton(){}
 public static Singleton getInstance()
 {
  if(UniqueInstance==null)UniqueInstance=new Singleton();
  return UniqueInstance;
 }
}

没有模块或函子,这是否可能?

问题回答

你能解释一下为什么模块解决方案对你不起作用吗?在其他语言中,模块确实是执行单例任务的自然方式。

一般而言,在OCaml中,GOF风格的模式基本上是不相关的。事实上,在OCaml中,对象基本上是不相关的。来自面向对象背景的人们常常认为他们应该从使用OCaml的面向对象特性开始,但这是一个错误。在OCaml中,大多数使用其他语言中的对象解决的问题都是使用参数多态性、代数数据类型和模块来解决的。Functor是一个稍微高级一些的主题,对象则是远离主流的。在成为这门语言的高级用户之前,不应该触及对象系统。

OCaml中的对象无法具有静态/全局方法。你可以尝试使用即时对象。需要注意的是,我认为您仍然可以使用obj.copy来获取对象的副本,并且每次它们被评估时都会返回一个新对象(因此您无法将参数传递给对象,好吧,您可以通过一些封装和全局布尔来做到这一点,但现在您正在处理模块)。当然,如果您只有像这样的示例,

let p = object 
   val mutable x = 0
   method get_x = x
   method move d = x <- x + d
end

p将被评估一次,然后您每次都可以访问它。当然,p#copy会为您搞砸一切。在这里,模块是解决问题的方式。Ocaml的面向对象特性并不像其他语言那样强大。当然,这个项目的目标并不是这个,它的模块系统非常强大。

模块是全局单例。你实际上不需要写任何东西来构建它们,它们隐含在语言中。例如,如何将日志记录到文件:

---logging.ml
(* default channel to log *)
let log_channel = ref stdout

(* set the log to a channel *)
let set_log_chan chan = log_channel := chan

(* timestamp of log -- kinda heavy weight, but just for kicks *)
let get_log_prequel () = 
    let time = Unix.localtime (Unix.time ()) in
    (* format the time data into "y/m/d - h:m:s" format *)
    Printf.sprintf  "%d/%02d/%02d - %02d:%02d:%02d"
                    (time.Unix.tm_year+1900) time.Unix.tm_mon time.Unix.tm_mday
                    time.Unix.tm_hour time.Unix.tm_min time.Unix.tm_sec

(* log a string to the channel *)
let log_string str =
    output_string (!log_channel) ((get_log_prequel ())^":	"^str^"
")

---logging.mli
set_log_chan : in_channel -> unit
log_string : string -> unit

我想你明白了这个要点。单例是隐式的对吧?不像对象那样有实例化的过程--但在单例中这是你想要的。你只需要在其他文件中开始使用它,就像这样:Logging.log_string "parsed file "^file_name^" successfully." 等等,任何地方都是一样的通道。

通过函数器,您可以组合您的模块以增加多样性。例如指定一个模块/函数来生成预备输出等。





相关问题
热门标签