Nadesłany przez Andrzej Borucki, 30 listopada 2012 11:41
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.Pobierz pełne rozwiązanie.
Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.
CommandGaussFrm.pas:
(****************************************** * Wzorzec Projektowy Command (polecenie) * * demonstrujący Eliminację Gaussa * * www.algorytm.org * * Kontakt * * borucki_andrzej (małpka) wp.pl * * Opracował Andrzej Borucki na podstawie * * opisu Arivalda na pl.comp.lang.delphi * ******************************************) unit CommandGaussFrm; interface uses Windows, Forms, Dialogs, StdCtrls, Classes, Controls, SysUtils; type TForm1 = class(TForm) Memo1: TMemo; InitButton: TButton; NextButton: TButton; PriorButton: TButton; CalculateButton: TButton; StartButton: TButton; procedure InitButtonClick(Sender: TObject); procedure CalculateButtonClick(Sender: TObject); procedure PriorButtonClick(Sender: TObject); procedure NextButtonClick(Sender: TObject); procedure StartButtonClick(Sender: TObject); procedure FormDestroy(Sender: TObject); private procedure EnableDisableButtons; public procedure print(); end; TModel = class; TCommand = class private Fmodel: TModel; public constructor Create(m: TModel); function _Do(): Boolean ; virtual; abstract; function Undo(): Boolean; virtual; abstract; function Describe(): string; virtual; abstract; end; TCommandProcessor = class private Fmodel: TModel; Fcommands: TList; FcurrentCommand: integer; public constructor Create(m: TModel); destructor Destroy(); override; function Execute(c: TCommand): Boolean; function CanUndo(): Boolean; function CanRedo(): Boolean; function Undo(): Boolean; function Redo(): Boolean; procedure RemoveRedo(); end; TModel = class public FA: array[0..2, 0..2] of Double; Fb: array[0..2] of Double; private FCommandProcessor: TCommandProcessor; public constructor Create(); destructor Destroy(); override; property CommandProcessor: TCommandProcessor read FCommandProcessor; end; var Form1: TForm1; implementation {$R *.DFM} uses Math; const DIM = 3; constructor TCommand.Create(m: TModel); begin Fmodel := m; end; function TCommandProcessor.CanRedo: Boolean; begin Result := FcurrentCommand < Fcommands.Count - 1; end; function TCommandProcessor.CanUndo: Boolean; begin Result := FcurrentCommand >= 0; end; constructor TCommandProcessor.Create(m: TModel); begin Fmodel := m; Fcommands := TList.Create(); FcurrentCommand := -1; end; destructor TCommandProcessor.Destroy(); begin inherited; FcurrentCommand := -1; RemoveRedo(); Fcommands.Free(); end; function TCommandProcessor.Execute(c: TCommand): Boolean; begin Result := c._Do(); if Result then begin //remove all "redo" data, because it will be not needed anymore if FcurrentCommand < Fcommands.Count - 1 then RemoveRedo(); Assert(Fcommands.Count - 1 = FcurrentCommand); Fcommands.Add(c); inc(FcurrentCommand); end else //fail begin c.Free(); raise Exception.Create('cammand fail'); end; end; function TCommandProcessor.Undo(): Boolean; begin Assert(FcurrentCommand >= 0); Result := TCommand(Fcommands[FcurrentCommand]).Undo(); if Result then Dec(FcurrentCommand); end; function TCommandProcessor.Redo(): Boolean; begin Assert(FcurrentCommand < Fcommands.Count - 1); Result := TCommand(Fcommands[FcurrentCommand + 1])._Do(); if Result then inc(FcurrentCommand); end; procedure TCommandProcessor.RemoveRedo(); var i: integer; begin for i := Fcommands.Count - 1 downto FcurrentCommand + 1 do try TCommand(Fcommands[i]).Free(); except Application.HandleException(Self); end; Fcommands.Count := FcurrentCommand + 1; end; constructor TModel.Create(); begin FCommandProcessor := TCommandProcessor.Create(Self); end; destructor TModel.Destroy(); begin FCommandProcessor.Free; inherited; end; //commands type TSetA = class(TCommand) private Fx, Fy: integer; FnewValue, FoldValue: Double; public constructor Create(m: TModel; x, y: integer; Value: Double); function _Do(): Boolean; override; function Undo(): Boolean; override; function Describe(): string; override; end; TSetB = class(TCommand) private Fidx: integer; FnewValue, FoldValue: Double; public constructor Create(m: TModel; idx: integer; Value: Double); function _Do(): Boolean; override; function Undo(): Boolean; override; function Describe(): string; override; end; constructor TSetA.Create(m: TModel; x, y: integer; Value: Double); begin inherited Create(m); Fx := x; Fy := y; FoldValue := NAN;//not disturb that FoldValue has no old value, it will set in _Do() FnewValue := Value; end; function TSetA._Do(): Boolean; begin FoldValue := Fmodel.FA[Fx, Fy]; Fmodel.FA[Fx, Fy] := FnewValue; Result := True; end; function TSetA.Undo(): Boolean; begin FnewValue := Fmodel.FA[Fx, Fy]; Fmodel.FA[Fx, Fy] := FoldValue; Result := True; end; function TSetA.Describe(): string; begin Result := Format('Set A[%d,%d] to %.4f (was %.4f)', [Fx, fy, FnewValue, FoldValue]); end; constructor TSetB.Create(m: TModel; idx: integer; Value: Double); begin inherited Create(m); Fidx := idx; FoldValue := NAN; FnewValue := Value; end; function TSetB._Do(): Boolean; begin FoldValue := Fmodel.Fb[Fidx]; Fmodel.Fb[Fidx] := FnewValue; Result := True; end; function TSetB.Undo(): Boolean; begin FnewValue := Fmodel.Fb[Fidx]; Fmodel.Fb[Fidx] := FoldValue; Result := True; end; function TSetB.Describe(): string; begin Result := Format('Set B[%d] to %.4f (was %.4f)', [Fidx, FnewValue, FoldValue]); end; var model: TModel = nil; procedure TForm1.print(); var s: string; i: integer; begin Memo1.Clear(); if not Assigned(model) then Exit; if model.CommandProcessor.Fcommands.Count > 0 then s := '(initial state)'; if (model.CommandProcessor.Fcommands.Count > 0) and (model.CommandProcessor.FcurrentCommand >= 0) then s := TCommand( model.CommandProcessor.Fcommands[ model.CommandProcessor.FcurrentCommand]).Describe(); Memo1.Lines.Add(Format('command: %d / %d; %s', [model.CommandProcessor.FcurrentCommand +1, model.CommandProcessor.Fcommands.Count, s])); Memo1.Lines.Add(Format('A:%sb:', [StringOfChar(' ', 61)])); Memo1.Lines.Add(Format('+%s+', [StringOfChar('-', 61)])); for i := 0 to DIM-1 do Memo1.Lines.Add(Format('| %12.4f | %12.4f | %12.4f || %12.4f |', [model.FA[i, 0], model.FA[i, 1], model.FA[i, 2], model.FB[i]])); Memo1.Lines.Add(Format('+%s+', [StringOfChar('-', 61)])); end; procedure TForm1.EnableDisableButtons; begin PriorButton.Enabled := model.CommandProcessor.CanUndo; NextButton.Enabled := model.CommandProcessor.CanRedo; end; procedure TForm1.FormDestroy(Sender: TObject); begin model.Free; end; procedure TForm1.InitButtonClick(Sender: TObject); begin model.Free; model := TModel.Create(); model.FA[0, 0] := 2; model.FA[0, 1] := 1; model.FA[0, 2] := -1; model.FA[1, 0] := -3; model.FA[1, 1] := -1; model.FA[1, 2] := 2; model.FA[2, 0] := -2; model.FA[2, 1] := 1; model.FA[2, 2] := 2; model.Fb[0] := 8; model.Fb[1] := -11; model.Fb[2] := 3; print(); CalculateButton.Enabled := True; end; procedure TForm1.CalculateButtonClick(Sender: TObject); var start: integer; i,j: integer; l: Double; begin print(); for start:=0 to DIM-2 do begin for i:=start+1 to DIM-1 do begin l:=model.FA[i,start]/model.FA[start,start]; for j:=start to DIM-1 do begin //model.FA[i,j]:=model.FA[i,j]-l*model.FA[start,j]; model.CommandProcessor.Execute(TSetA.Create(model, i, j, model.FA[i,j]-l*model.FA[start,j])); end; //model.Fb[i]:=model.Fb[i]-l*model.Fb[start]; model.CommandProcessor.Execute(TSetB.Create(model, i, model.Fb[i]-l*model.Fb[start])); end; end; print(); EnableDisableButtons; StartButton.Enabled := True; end; procedure TForm1.PriorButtonClick(Sender: TObject); begin model.CommandProcessor.Undo(); print(); EnableDisableButtons; end; procedure TForm1.StartButtonClick(Sender: TObject); begin with model.CommandProcessor do while CanUndo do Undo(); print(); EnableDisableButtons; end; procedure TForm1.NextButtonClick(Sender: TObject); begin model.CommandProcessor.Redo(); print(); EnableDisableButtons; end; end.