《GOF设计模式》—生成器(Builder)—Delphi源码示例:RTF阅读器

示例:RTF阅读器

特点:

通常情况下,由具体生成器生成的产品,它们的表示相差是如此之大以至于给不同的产品以公共父类没有太大意思。因为客户通常用合适的具体生成器来配置导向者,客户处于的位置使它知道Builder的哪一个具体子类被使用,以及能处理具体Builder生成的产品。

实现:

一个RTFRichTextFormat)文档交换格式的阅读器应能将RTF转换为多种正文格式,如该阅读器可以将RTF文档转换成普通ASCII文本。但问题在于“格式转换”的数目可能是无限的。因此要求能够很容易的实现新的格式转换,同时却无需改变RTF阅读器的实现。

一个解决办法是用一个可以将RTF转换成另一种正文表示的“TextConverter对象”来配置“RTFReader对象”。当RTFReaderRTF文档进行语法分析时,它使用TextConverter去做转换。无论何时RTFReader识别了一个RTF标记(或是普通正文或是一个RTF控制字),它都发送一个请求给TextConverter去转换这个标记。TextConverter对象负责进行数据转换以及用特定格式表示该标记,如下图所示。

 

TextConvert的子类对不同转换和不同格式进行特殊处理。例如,一个ASCIIConverter只负责转换普通文本,而忽略其他转换请求。另一方面,一个TeXConverter将会为实现对所有请求的操作,以便生成一个获取正文中所有风格信息的TEX表示。一个TextWidgetConverter将生成一个复杂的用户界面对象以便用户浏览和编辑正文。

每种转换器类将创建和装配一个复杂对象的机制隐含在抽象接口的后面。转换器独立于阅读器,阅读器负责对一个RTF文档进行语法分析。

Builder模式描述了所有这些关系。每一个转换器类在该模式中被称为生成器(builder),而阅读器则称为导向器(director)。在上面的例子中,Builder模式将分析文本格式的算法(即RTF文档的语法分析程序)与描述怎样创建和表示一个转换后格式的算法分离开来。这使我们可以重用RTFReader的语法分析算法,根据RTF文档创建不同的正文表示­——仅需使用不同的TextConverter的子类配置该RTFReader即可。

代码:

 

unit uRTFReader;

 

interface

 

uses

    Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs;

 

type

    TTokenType = (ttCHAR,ttFONT,ttPARA);

 

    TToken = record

        FType: TTokenType;

        FChar: Char;

        FFont: string;

    end;

    PToken = ^TToken;

 

    TTokenIterator = class;

 

    TTokenList = class

    private

        FDataList: TList;

        function GetCount: Integer;

        function GetItems(Index: integer): PToken;

    public

        constructor Create;

        destructor Destroy; override;

        //---

        function Add(const Token: TToken): Boolean;

        procedure Clear;

        function CreateIterator: TTokenIterator;

        //---

        property Count: Integer read GetCount;

        property Items[Index: integer]: PToken read GetItems;default;

    end;

 

    TTokenIterator = class

    private

        FTokens: TTokenList;

        FCurIndex: integer;

        function GetToken: PToken;

    public

        constructor Create(Tokens: TTokenList);

        //---

        procedure First;

        procedure Last;

        procedure Next;

        procedure Prev;

        //---

        function BOF: Boolean;

        function EOF: Boolean;

        //--

        property Token: PToken read GetToken;

    end;

 

    TASCIIText = class

    private

        FText: string;

    public

        property Text: string read FText write FText;

    end;

 

    TTeXText = class

    end;

 

    TTextWidget = class

    end;

 

    TTextConverter = class

    public

        procedure ConvertCharacter(AChar: Char); virtual;

        procedure ConvertFontChange(Font: string); virtual;

        procedure ConvertParagraph(); virtual;

    end;

 

    TASCIIConverter = class(TTextConverter)

    private

        FASCIIText: TASCIIText;

    public

        constructor Create;

        //---

        procedure ConvertCharacter(AChar: Char); override;

        function GetASCIIText: TASCIIText;

    end;

 

    TTeXConverter = class(TTextConverter)

    private

        FTeXText: TTeXText;

    public

        constructor Create;

        //---

        procedure ConvertCharacter(AChar: Char); override;

        procedure ConvertFontChange(Font: string); override;

        procedure ConvertParagraph; override;

        function GetTeXText: TTeXText;

    end;

 

    TTextWidgetConverter = class(TTextConverter)

    private

        FTextWidget: TTextWidget;

    public

        constructor Create;

        //---

        procedure ConvertCharacter(AChar: Char); override;

        procedure ConvertFontChange(Font: string); override;

        procedure ConvertParagraph; override;

        function GetTextWidget: TTextWidget;

    end;

 

    TRTFReader = class

    private

        FTokens: TTokenList;

    public

        constructor Create(Tokens: TTokenList);

        //---

        procedure ParseRTF(Builder: TTextConverter);

    end;

 

implementation

 

procedure TTextConverter.ConvertCharacter(AChar: Char);

begin

 

end;

 

procedure TTextConverter.ConvertFontChange(Font: string);

begin

 

end;

 

procedure TTextConverter.ConvertParagraph;

begin

 

end;

 

constructor TASCIIConverter.Create;

begin

    FASCIIText := nil;

end;

 

procedure TASCIIConverter.ConvertCharacter(AChar: Char);

begin

    if FASCIIText = nil then

        FASCIIText := TASCIIText.Create;

    //---

    FASCIIText.Text := FASCIIText.Text + AChar;

end;

 

function TASCIIConverter.GetASCIIText: TASCIIText;

begin

    Result := FASCIIText;

end;

 

constructor TTeXConverter.Create;

begin

    FTeXText := nil;

end;

 

procedure TTeXConverter.ConvertCharacter(AChar: Char);

begin

 

end;

 

procedure TTeXConverter.ConvertFontChange(Font: string);

begin

 

end;

 

procedure TTeXConverter.ConvertParagraph;

begin

 

end;

 

function TTeXConverter.GetTeXText: TTeXText;

begin

    Result := FTeXText;

end;

 

constructor TTextWidgetConverter.Create;

begin

    FTextWidget := nil;

end;

 

procedure TTextWidgetConverter.ConvertCharacter(AChar: Char);

begin

 

end;

 

procedure TTextWidgetConverter.ConvertFontChange(Font: string);

begin

 

end;

 

procedure TTextWidgetConverter.ConvertParagraph;

begin

 

end;

 

function TTextWidgetConverter.GetTextWidget: TTextWidget;

begin

    Result := FTextWidget;

end;

 

constructor TRTFReader.Create(Tokens: TTokenList);

begin

    FTokens := Tokens;

end;

 

procedure TRTFReader.ParseRTF(Builder: TTextConverter);

var

    Iterator: TTokenIterator;

begin

    Iterator := FTokens.CreateIterator;

    try

        with Iterator do

        begin

            First;

            while not EOF do

            begin

                case Token.FType of

                    ttCHAR: Builder.ConvertCharacter(Token.FChar);

                    ttFONT: Builder.ConvertFontChange(Token.FFont);

                    ttPARA: Builder.ConvertParagraph;

                end;

                //---

                next;

            end;

        end;

    finally

        Iterator.Free;

    end;

end;

 

constructor TTokenList.Create;

begin

    inherited;

    //---

    FDataList := TList.Create;

end;

 

destructor TTokenList.Destroy;

begin

    Clear;

    FDataList.Free;

    //---

    inherited;

end;

 

procedure TTokenList.Clear;

var

    i: Integer;

    pData: PToken;

begin

    with FDataList do

    begin

        for i := 0 to Count - 1 do

        begin

            pData := Items[i];

            Dispose(pData);

        end;

        Clear;

    end;

end;

 

function TTokenList.Add(const Token: TToken): Boolean;

var

    pData: PToken;

begin

    new(pData);

    pData^ := Token;

    FDataList.Add(pData);

end;

 

function TTokenList.GetCount: Integer;

begin

    Result := FDataList.Count;

end;

 

function TTokenList.GetItems(Index: integer): PToken;

begin

    Result := FDataList[Index];

end;

 

constructor TTokenIterator.Create(Tokens: TTokenList);

begin

    FTokens := Tokens;

    FCurIndex := 0;

end;

 

function TTokenIterator.BOF: Boolean;

begin

    Result := FCurIndex <= 0;

end;

 

function TTokenIterator.EOF: Boolean;

begin

    Result := FCurIndex >= FTokens.Count;

end;

 

procedure TTokenIterator.First;

begin

    FCurIndex := 0;

end;

 

function TTokenIterator.GetToken: PToken;

begin

    Result := FTokens[FCurIndex];

end;

 

procedure TTokenIterator.Last;

begin

    FCurIndex := FTokens.Count - 1;

end;

 

procedure TTokenIterator.Next;

begin

    FCurIndex := FCurIndex + 1;

end;

 

procedure TTokenIterator.Prev;

begin

    FCurIndex := FCurIndex - 1;

end;

 

function TTokenList.CreateIterator: TTokenIterator;

begin

    Result := TTokenIterator.Create(self);

end;

 

end.

 

procedure TForm1.Button1Click(Sender: TObject);

var

    Tokens: TTokenList;

    Reader: TRTFReader;

    Converter: TASCIIConverter;

    ASCIIText: TASCIIText;

    //---

    procedure _AddToken;

    var

        Token: TToken;

    begin

        with Token do

        begin

            FType := ttCHAR;

            FChar := 'A';

            FFont := '';

        end;

        Tokens.Add(Token);

        //---

        with Token do

        begin

            FType := ttFONT;

            FChar := ' ';

            FFont := '宋体 9';

        end;

        Tokens.Add(Token);

        //---

        with Token do

        begin

            FType := ttPARA;

            FChar := ' ';

            FFont := '';

        end;

        Tokens.Add(Token);

        with Token do

        begin

            FType := ttCHAR;

            FChar := 'B';

            FFont := '';

        end;

        Tokens.Add(Token);

    end;

begin

    Tokens := TTokenList.Create;

    Reader := TRTFReader.Create(Tokens);

    Converter := TASCIIConverter.Create;

    //--

    _AddToken;

    Reader.ParseRTF(Converter);

    ASCIIText := Converter.GetASCIIText;

    showmessage(ASCIIText.Text);

    //---

    ASCIIText.Free;

    Converter.Free;

    Reader.Free;

    Tokens.Free;

end;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值