设计模式之工厂方法(FACTORY METHOD)

 

工厂方法

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

派生类为这个选拔基类(Seeding)分别建立一个实例来调用这些方法。我们现在建立这两个具体的选拔子类:StraightSeeding CircleSeeding类。PrelimEvent类将返回CircleSeeding类的实例,TimedFinalEvent类则返回StraightSeeding类实例。

结构如下:

 

  

通过整个事件层次,可以看到PrelimEvent类、TimedFinalEvent类都包含getSeeding方法,PrelimEvent类将返回CircleSeeding类的实例,TimedFinalEvent类则返回StraightSeeding类实例。在这个简单的例子当中我们并没有指出真正的工厂(Factory),然而,实例化哪一个Event类决定了哪一个Seeding类将被实例化。

       虽然它看起来像是在两个类之间存在一对一相应的通信。 但,这不是必需的。可以有许多不同类型的Events类但他们只使用少一部分Seeding类。

 

Swimmer

      Swimmer类包含一些游泳运动员的具体信息和在选拔之后修改运动员的组以及泳道的方法。Event类在数据库(在这个例子中为文本文件)读取运动员信息。当调用Event类的getSeeding方法时将这个运动员的集合传递到Seeding类。

 

Events

      我们已经定义了一个抽象基类,在实际的应用当中,我们只是使用它来读取游泳运动员的数据信息(在这个例子中为文本文件)。

 

Prelimevent类返回CircleSeeding实例

 

Public Class Prelimevent

    Inherits Events

        Dim sd As Seeding

    Public Overrides Function getSeeding() As Seeding

        Return New CircleSeeding(swmmers, numLanes)

    End Function

   

    Public Overrides Function isFinal() As Boolean

        isFinal = False

    End Function

   

    Public Overrides Function isPrelim() As Boolean

        isPrelim = True

    End Function

   

    Public Overrides Function isTimedFinal() As Boolean

        isTimedFinal = False

    End Function

   

    Public Sub New(ByVal Filename As String, ByVal lanes As Integer)

        MyBase.New(Filename, lanes)

        numLanes = lanes

    End Sub

End Class

 

TimedFinalEvent类返回StraightSeeding实例

 

public Class TimedFinalEvent

    Inherits Events

 

    Public Sub New(ByVal Filename As String, ByVal lanes As Integer)

        MyBase.New(Filename, lanes)

    End Sub

    '------   

    Public Overrides Function getSeeding() As Seeding

        Dim sd As Seeding

        'create seeding and execute it

        sd = New StraightSeeding(swmmers, numLanes)

        sd.seed()

        getSeeding = sd

    End Function

    '------   

    Public Overrides Function isFinal() As Boolean

        isFinal = False

    End Function

    '------

    Public Overrides Function isPrelim() As Boolean

        isPrelim = False

    End Function

    '------

    Public Overrides Function isTimedFinal() As Boolean

        isTimedFinal = True

    End Function

 

End Class

Straight Seeding

 

在这个小程序在实际应用当中,会发现大部分工作在Straight Seeding类中完成的。我们实例化StraightSeeding 类,复制、修改游泳运动员的集合和所属泳道位置。

 

Public Class StraightSeeding

    Inherits Seeding

    Public Overrides Sub seed()

        Dim lastHeat As Integer

        Dim lastlanes As Integer

        Dim i, j, count, heats As Integer

        Dim swmr As Swimmer

        Try

            sw = sort(sw)

            laneOrder = calcLaneOrder(numLanes)

            count = sw.Count

            lastHeat = count Mod numLanes

            If (lastHeat < 3) And lastHeat > 0 Then

                lastHeat = 3   'last heat must have 3 or more

            End If

            count = sw.Count

            lastlanes = count - lastHeat

            numheats = lastlanes / numLanes

            If (lastHeat > 0) Then

                numheats = numheats + 1

            End If

            heats = numheats

            'place heat and lane in each swimmer's object

            j = 0

            For i = 0 To lastlanes - 1

                swmr = sw.swm(i)

                swmr.setLane(CType(laneOrder(j), Integer))

                j = j + 1

                swmr.setHeat(heats)

                If (j >= numLanes) Then

                    heats = heats - 1

                    j = 0

                End If

            Next i

            'Add in last partial heat

            If (lastHeat > 0) Then

                If j > 0 Then

                    heats = heats - 1

                End If

                j = 0

                For i = lastlanes To count - 1

                    swmr = CType(sw(i), Swimmer)

                    swmr.setLane(CType(laneOrder(j), Integer))

                    j = j + 1

                    swmr.setHeat(heats)

                Next i

            End If

 

        Catch e As Exception

            Console.WriteLine(i.ToString + j.ToString + e.ToString)

            Console.WriteLine(e.StackTrace)

        End Try

    End Sub

    '-----

    Public Sub New(ByVal swmrs As Swimmers, ByVal lanes As Integer)

        MyBase.new(swmrs, lanes)

    End Sub

End Class

    当调用getSwimmers方法时,StraightSeeding 类将创建被选拔的游泳运动员数组。

Circle Seeding

 

CircleSeeding 是从StraightSeeding 类派生的。

 

Public Class CircleSeeding

    Inherits StraightSeeding

   

    Private circlesd As Integer

    '-----

    Public Sub New(ByVal swmrs As Swimmers, ByVal lanes As Integer)

        MyBase.New(swmrs, lanes)

       

    End Sub

    '-----

    Public Overrides Sub seed()

       

        Dim i, j, k, numHeats As Integer

        laneOrder = calcLaneOrder(numLanes)

        sw = sort(sw)    '排序

       

        MyBase.seed()          

        numheats = MyBase.getHeats

           If (numheats >= 2) Then

            If (numheats >= 3) Then

                circlesd = 3               

 Else

                circlesd = 2              

            End If

            i = 0

           

            For j = 0 To numLanes - 1

                For k = 1 To circlesd

                    sw.swm(i).setLane(CType(laneOrder(j), Integer))

                    sw.swm(i).setHeat(numheats - k + 1)

                    i = i + 1

                Next k

            Next j

        End If

    End Sub

    '-----

End Class

 

运行

      在这个例子当中,我们使用完成500m自由泳和100m自由泳的运动员列表来创建TimedFinalEvent 类和PrelimEvent类。


 

选择自 guoyan19811021 的 Blog
作者Blog:http://blog.csdn.net/guoyan19811021/







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值