第1章 元这个字眼
元编程是编写能写代码的代码
1.1 鬼城与自由市场
语言构件(language construct)包含各种成员(变量、类、方法等)。
以C++为例,一旦编译器完成了工作,变量和函数这样的东西就变得看不见摸不着了,它们只存在于内存中。你没有办法向一个类询问它的实例方法,因为当你问出这个问题时,它可能已经消失了。对于C++这样的语言来说,运行时(runtime)是一个可怕的寂静之地----鬼城。
而在另外一些语言(如Ruby)中,运行时更像是一个繁忙的自由市场。大多数语言构件依然存在,而且正四处忙碌着。你甚至可以抓住一个构件,询问它关于它自身的问题。这种方式称作内省(introspection)
让我们通过一个实例来看看内省究竟是什么。
class Greeting
def initialize(text)
@text = text
end
def welcome
@text
end
end
复制
my_object = Greeting.new("Hello")
这里定义了一个Greeting类,并创建了一个Greeting对象。现在我们可以抓住这个对象,并像它提问:
my_object.class #=> Greeting
我问它所属的类,它十分肯定的回答我:“我是一个Greeting”,现在我要问它有哪些实例方法:
my_object.class.instance_methods(false) #=> [:welcome]
我得到的回答是一个数组,其中只有一个方法welcome。参数false代表我是问它自己的方法,不要它继承来的方法。接着,我问它有哪些实例变量:
my_object.instance_variables #=> [:@text]
它如实回答了我的问题。类和对象都是Ruby世界的一等公民,你可以问出很多信息来。

ruby
Ruby除了可以在运行时询问语言构件,还能在运行时创建它们。在程序运行时,能否在welcome方法之外再添加一个实例方法?你可能不太理解,究竟什么情况下会有这样的需求呢?请看下面的故事。
1.2 程序员Bob的故事
Bob有一个计划:为电影迷建造一个世界最大的互联网社交系统。为了实现这个目标,他先要建立一个存放电影名和影评的数据库。Bob希望借此机会练习编写可重用的代码,因此他决定创建一个简单的代码库,用于在数据库中实现对象的持久化。
1.2.1 Bob的第一次尝试
Bob编写了一个代码库,把数据库中的每个表映射到一个类中,同时把每条记录映射到一个对象中。每当创一个对象或访问它的属性时,这个对象会产生一条SQL语句并发送给数据库。所有这些功能都封装在一个类中。
class Entity
attr_reader :table, :ident
def initialize(table, ident)
@table = table
@ident = ident
Database.sql "INSERT INTO #{@table} (id) VALUES (#{@ident})"
end
def set(col, val)
Database.sql "UPDATE #{@table} SET #{col}='#{val}' WHERE id=#{@ident}"
end
def get(col)
Database.sql ("SELECT #{col} FROM #{@table} WHERE id=#{@ident}")[0][0]
end
end
复制
在Bob的数据库中,每个表都有一个id字段。每个Entity会保存这个字段的内容以及它引用的表名。每创建一个Entity对象后,该对象会把自己保存在数据库里。Entity#set方法创建SQL语句更新字段值,而Entity#get方法创建SQL语句读取字段值。(Bob的Database类用二维数组作为返回的数据集)
Bob可以继承Entity类来映射一个指定的表。例如,用Movie类映射一个名为movies的表:
class Movie < Entity
def initialize(ident)
super "movies", ident
end
def title
get "title"
end
def title=(value)
set "title", value
end
def director
get "director"
end
def director=(value)
set "director", value
end
end
复制
Movie类的每个属性有两个方法:一个读方法和一个写方法。Bob只要在Ruby命令行解释器中输入如下命令,就能把一部电影加载到数据库里:
movie = Movie.new(1)
movie.title = "Doctor Strangelove"
movie.director = "Stanley Kubrick"
复制
Bill看了Bob的代码后说:“重复的代码太多了。数据库里有title字段,代码里有@title成员,还有title方法、title=方法、title字符串常量。如果你会元编程,用很少的代码就可以解决这个问题。”
1.2.2 进入元编程的世界
==未完待续==