工厂方法
the factory method
我们已经学会了简单工厂模式(simple factory pattern),工厂(factory)思想贯穿于整个面向对象编程(oop)以及其他一些设计模式的始终。如:生成器(builder)模式。其间,一个单一的类扮演类似交通警察的角色,决定哪一个单一层次上的子类将被实例化。
工厂方法模式(factory method pattern)是对工厂(factory)思想进行了巧妙的延伸,它使得将超类的实例化延迟到它的每一个子类。这个模式没有具体的指出延迟到哪一个子类,而是定义一个抽象类创建对象,让其子类决定创建哪一个对象。
下面是一个简单的例子,在一个游泳比赛中如何确定游泳运动员的泳道。按照运动员的成绩排列决赛事的分组,速度越快所分的小组的决赛的次序越靠后,反之,速度越慢就越先比赛,而且在每一个小组中成绩越好、速度越快的选手也就越靠近中间的泳道。这被称为straight seeding。
当游泳运动员在锦标赛比赛过程中,他们通常要游两次。 通过在预赛中相互竞争,前12名或者16名游泳运动员将继续在决赛中继续彼此竞争。 为了预赛工作更公平, 采用circle seeded,这样使得速度最快的3名选手分别处于最迅速3个小组的中心泳道。在剩下的选手中再选出速度最好的3名选手,等等。
我们要实现这个选拔模式并且使用工厂方法。
首先,设计抽象事件类:
public class events
protected numlanes as integer
protected swmmers as swimmers
—–
public sub new(byval filename as string, byval lanes as integer)
mybase.new()
dim s as string
dim sw as swimmer
dim fl as vbfile
fl = new vbfile(filename) 打开一个文本文件
fl.openforread()
numlanes = lanes 保存泳道数量信息
swmmers = new swimmers
读取游泳选手信息
s = fl.readline
while not fl.feof
sw = new swimmer(s) 建立对象
swmmers.add(sw) add to list
s = fl.readline
end while
fl.closefile()
end sub
—–
public function getswimmers() as arraylist
getswimmers = swmmers
end function
—–
public overridable function isprelim() as boolean
end function
—–
public overridable function isfinal() as boolean
end function
—–
public overridable function istimedfinal() as boolean
end function
—–
public overridable function getseeding() as seeding
end function
end class
因为所有的派生类都要从文本文件读取数据,所以,我们把events类作为基类。其中所定义的方法均为虚方法,可以通过继承events类来实现具体的类(prelimevent类、timedfinalevent类),这两个类之间唯一的不同就是返回的选拔的类别不同。我们也定义了一个包含以下方法的抽象选拔类:
public mustinherit class seeding
protected numlanes as integer
protected laneorder as arraylist
protected numheats as integer
private asw() as swimmer
protected sw as swimmers
—–
public function getseeding() as swimmers
getseeding = sw
end function
—–
public function getheat() as integer
end function
—–
public function getcount() as integer
getcount = sw.count
end function
—–
public mustoverride sub seed()
—–
public function getswimmers() as arraylist
getswimmers = sw
end function
—–
public function getheats() as integer
return numheats
end function
—–
public function odd(byval n as integer) as boolean
odd = (n \ 2) * 2 <> n
end function
—–
public function calclaneorder(byval lns as integer) as arraylist
numlanes = lns
dim lanes(numlanes) as integer
dim i as integer
dim mid, incr, ln as integer
mid = (numlanes \ 2)
if (odd(numlanes)) then
mid = mid + 1
end if
incr = 1
ln = mid
for i = 0 to numlanes – 1
lanes(i) = ln
ln = mid + incr
incr = -incr
if (incr > 0) then
incr = incr + 1
end if
next i
laneorder = new arraylist
for i = 0 to numlanes – 1
laneorder.add(lanes(i))
next i
calclaneorder = laneorder
end function
public sub new(byval swmrs as swimmers, byval lanes as integer)
mybase.new()
sw = swmrs
numlanes = lanes
end sub
——————-
public function sort(byval sw as swimmers) as swimmers
dim i, j, max as integer
dim tmp as swimmer
try
max = sw.count
dim asw(max) as swimmer
for i = 0 to max – 1
asw(i) = ctype(sw.item(i), swimmer)
next i
for i = 0 to max – 1
for j = i to max – 1
if asw(i).gettime > asw(j).gettime then
tmp = asw(i)
asw(j) = asw(i)
asw(i) = tmp
end if
next j
next i
sw = new swimmers
for i = 0 to max – 1
sw.add(asw(i))
next i
sort = sw
catch e as exception
console.writeline("caught " + i.tostring + " " + j.tostring + " " + max.tostring + " " + e.tostring())
console.writeline(e.stacktrace)
end try
end function
end class