Esta noche anterior, leía el último artículo de Nico Aragon que publicaba en su bitácora:
El cortador de lineas
y tras analizar el código, le hice algunos comentarios que me parecían de interés. De hecho, he leido su respuesta y creo que estamos básicamente de acuerdo en lo de objetos «inteligentes o tontos», o como el llama «activos o pasivos». Lo de menos es quizás el nombre sino el concepto que queda en el transfondo.
Acabo de modificar un poquito su código para que si algún compañero no lo ve, pueda apreciar la distinción a la que me refiero.
En el caso de esta unidad, la invocación del proceso cortador de lineas se haría mas o menos así, con la modificación o variación propuesta:
Cutter := TLineCutter.Create(//aquí el parámetro de tipo string); try Cutter.OnNewLine := AddLine; Cutter.Start; finally Cutter.Free; end;
La diferencia entre un objeto u otro, es simplemente sobre quien recae la responsabilidad del analisis y de determinar cuando ha finalizado. Relacionado con este punto, he suprimido el estado de finalización por una función de control Eof, que le indica al objeto cuando ha finalizado el análisis.
Realmente hacen los dos objetos, el de Nico, o esta variación exactamente lo mismo, y responden los dos al mismo diagrama de estados que planteó como fondo de su propuesta.
Lo dificil en todos estos casos, no es plantear modificaciones, sino esa primera fase de análisis del algoritmo. A posteriori, siempre es relativamente fácil encontrar optimizaciones sobre algo que ya tienes planteado previamente. Y en ese sentido, le doy toda la razón a Nico cuando explica en las primeras lineas de su artículo, la necesidad de apoyarnos en razonamientos formales, como pueda ser un diagrama de estados para la implementación de un algoritmo determinado.
//variacion de la unidad LineCutters //******************************
unit LineCutters; interface type TOnNewLineEvent = procedure(const Line: string) of object; TNotifyEvent = procedure(Sender: TObject) of object; TLineCutterState = (stText, stCR, stCRLF, stLF); TLineCutter = class private Buffer: String; FIndex: Integer; FActive: Boolean; FOnFinish: TNotifyEvent; FOnNewLine: TOnNewLineEvent; protected FTexto: string; State: TLineCutterState; procedure Process(const c: Char); procedure ReportLine; procedure DoProcess; virtual; procedure DoFinish; virtual; function EOF: Boolean; public constructor Create(const ACadena: String); virtual; procedure Start; property Active: Boolean read FActive; property OnNewLine: TOnNewLineEvent read FOnNewLine write FOnNewLine; property OnFinish: TNotifyEvent read FOnFinish write FOnFinish; end; implementation uses SysUtils; { TLineCutter } constructor TLineCutter.Create(const ACadena: String); begin inherited Create; FActive := False; FTexto := ACadena; State := stText; end; function TLineCutter.EOF: Boolean; begin Result:= FIndex > Length(FTexto); end; procedure TLineCutter.Process(const c: Char); begin case State of stText: begin if c = #13 then begin ReportLine; State := stCR; end else if c = #10 then begin ReportLine; State := stLF; end else begin Buffer := Buffer + c; end; end; stCr: begin if c = #13 then begin ReportLine; end else if c = #10 then begin State := stCRLF; end else begin Buffer := Buffer + c; State := stText; end; end; stLf: begin if c = #13 then begin ReportLine; State := stCR; end else if c = #10 then begin ReportLine; State := stLF; end else begin Buffer := Buffer + c; State := stText; end; end; stCRLF: begin if c = #13 then begin ReportLine; State := stCR; end else if c = #10 then begin ReportLine; State := stLF; end else begin Buffer := Buffer + c; State := stText; end; end; end; end; procedure TLineCutter.DoProcess; begin //prevenimos que no se pueda invocar si está en proceso FActive:= True; FIndex:= 1; Buffer:= ''; while not Eof do begin Process(FTexto[FIndex]); Inc(FIndex); end; if Buffer <> '' then ReportLine; //marcamos el final del algoritmo FActive:= False; end; procedure TLineCutter.ReportLine; begin if Assigned(FOnNewLine) then FOnNewLine(Buffer); Buffer := ''; end; procedure TLineCutter.DoFinish; begin if Assigned(FOnFinish) then FOnFinish(self); end; procedure TLineCutter.Start; begin if FActive then Raise Exception.Create('TLineCutter: In process'); DoProcess; DoFinish; //comunicamos al usuario que el algoritmo finalizó end; end.
Comentarios recientes