这是个非常有趣的模式,为什么呢?因为有些Programming Language在语言机制上就给予了支持,有些语言则没有。更有趣的是,有些语言可以简单的利用某些机制来实现强大的原型模式。
首先我们先来了解一下什么是原型模式,它首先是一个Creational Pattern,所以该模式的目的就是为了创建对象,我们通常都是new一个对象,而这个模式则是通过Clone一个已有的对象从而产生新的可供使用的对象。那到底new一个对象和clone一个对象的区别在哪里呢?下面举个简单的例子(为了简单,以java为例),前提-ClassA是ClassB和ClassC的父类。
ClassB obj = new ClassB();
// we assume po is prototype obj of ClassB.
ClassB obj = po.clone();
我们不难发现一个问题,通过new的方式我们生成一个对象时ClassB是不能被参数化的,除非采用模板机制;而通过clone则完全不同,因为po是可以参数化的。下面给出一段客户端代码:
// Here, po can be ClassA or ClassB or ClassC.
void operation(ClassA po) {
ClassA obj = po.clone;
}
void operation(String type){
ClassA obj = null;
if(type.equals("ClassB")) {
obj = new ClassB();
} else if(type.equals("ClassC")) {
obj = new ClassC();
}
}
很明显第二种客户端几乎是紧耦合的代表性人物。通过以上阐述可能我们现在已经发现问题的本质了,也就是怎样通过类的类型信息来生成类的实例。
我们主要从三种语言的角度进行相关的分析(C++, Java, Javascript):
首先我们来看C++,C++这种语言在语言机制上没有相应的机制来根据类的类型信息来生成类的实例,所以在C++中只能通过类的实例来识别类型,并调用当前实例的clone方法来生成新的类。
下面我们来看看Java,对于像C++那种原型模式,Java是Native Support。为什么说Java有趣的,是因为Java有两个非常有趣的机制:Class类型和Reflection。首先Class类型具备了持有类的类型的能力,这样就能够把类型参数化了,然后呢,反射机制又能够通过Class类生成新的对象。通过这样的机制,我们的客户端代码变的挺有趣的:
void operation(Class prototype){
ClassA obj = prototype.newInstance();
}
这样一来,我们的原型就成了Class了。Prototype Manager就变成了虚拟机的ClassLoader了。
下面我们再来看看Javascript,由于Javascript强大的反射机制使的在js中使用模板简直就像在玩儿,我们来看个例子:
void operation(/* String */ prototype){
var obj = eval(prototype);
}
// call code
operation("new MyObj(\"Hello\")");
这样一来,我们的原型成了String类型的实例了,而且由于是String,我们的还可以传参数呢。
综上所述,原型模式其实就是要想办法把类的类型具象化成一种可以携带类型的装置,然后利用语言的特性根据该装置生成新的类的实例。
没有评论:
发表评论