2015-12-08 4 views
0

Я работаю над проектом, в котором я построил структуру, состоящую из базового класса «TFuncao», двух классов потомков «TSolicitacao», «TResposta» и столько, сколько необходимо для классов потомков, все они являются классами-моделями только со свойствами.String to Class: класс преобразования или базовый метод преобразования?

Первый из них в центре внимания этого вопроса, он имеет метод «ParaTexto», который возвращает строку всех своих свойств определенным образом (в основном преобразуя их в строку). Этот класс «TSolicitacao» имеет много потомков, и каждый из них имеет метод «ParaTexto», вызывающий функцию своего предка и добавляющий его собственные свойства.

Итак, мой вопрос:

Должен ли я сохранить этот метод "ParaTexto"? Или удалить его и создать класс с методом, который получает «TSolicitacao» и, соответственно, его тип (класс потомков), возвращает строку?

Я думал об этом, потому что класс модели технически должен иметь только геттеры и сеттеры.

код - методы получения и установки, где удалены для экономии места:

"TFuncao" файл класса:

unit Funcao; 

interface 

uses 
    Funcao.Tipo; 

type 
    TFuncao = class abstract 
    private 
    FFUNCAO: TFuncaoTipo; 
    FSEQUENC: string; 
    procedure SetFUNCAO(const Value: TFuncaoTipo); 
    procedure SetSEQUENC(const Value: string); 
    published 
    property SEQUENC: string read FSEQUENC write SetSEQUENC; 
    property FUNCAO: TFuncaoTipo read FFUNCAO write SetFUNCAO; 
    constructor Create; virtual; 
    end; 

"TSolicitacao" файл класса:

unit Funcao.Solicitacao; 

interface 

uses 
    Funcao; 

type 
    TSolicitacao = class abstract (TFuncao) 
    published 
    function ParaTexto: string; virtual; 
    end; 

implementation 

uses 
    Funcoes, 
    SysUtils; 

{ TSolicitacao } 

function TSolicitacao.ParaTexto: string; 
begin 
    Result := 
    Copy(CompletarComEspacoAEsquerda(SEQUENC, 4), 1, 4) + 
    Completar0AEsquerda(IntToStr(Integer(FUNCAO)), 2); 
end; 

end. 

"TVendaSolicitacao" класса файл - пример класса потомков «TSolicitacao»:

unit Venda.Solicitacao; 

interface 

uses 
    Funcao.Solicitacao, 
    Funcao.Tipo, 
    Venda.Solicitacao.Produto; 

type 
    TVendaSolicitacao = class (TSolicitacao) 
    private 
    FNUMFISCAL: Integer; 
    FNUMPDV: Integer; 
    FAUTORIZ: string; 
    FCONV_TIPO: Integer; 
    FProdutos: TVendaSolicitacaoProdutoList; 
    procedure SetAUTORIZ(const Value: string); 
    procedure SetCONV_TIPO(const Value: Integer); 
    procedure SetNUMFISCAL(const Value: Integer); 
    procedure SetNUMPDV(const Value: Integer); 
    procedure SetProdutos(const Value: TVendaSolicitacaoProdutoList); 
    published 
    property NUMPDV: Integer read FNUMPDV write SetNUMPDV; 
    property NUMFISCAL: Integer read FNUMFISCAL write SetNUMFISCAL; 
    property AUTORIZ: string read FAUTORIZ write SetAUTORIZ; 
    property CONV_TIPO: Integer read FCONV_TIPO write SetCONV_TIPO; 
    property Produtos: TVendaSolicitacaoProdutoList read FProdutos write SetProdutos; 
    function ParaTexto: string; override; 
    constructor Create; override; 
    end; 

implementation 

uses 
    SysUtils, 
    Funcoes; 

{ TVendaSolicitacao } 

constructor TVendaSolicitacao.Create; 
begin 
    inherited; 
    FUNCAO := ftVenda; 
    FProdutos := TVendaSolicitacaoProdutoList.Create; 
end; 

function TVendaSolicitacao.ParaTexto: string; 
begin 
    Result := 
    inherited + 
    Completar0AEsquerda(NUMPDV, 4) + 
    Completar0AEsquerda(NUMFISCAL, 6) + 
    Completar0AEsquerda(AUTORIZ, 12) + 
    IntToStr(CONV_TIPO); 

    if Produtos.Count > 0 then 
    Result := Result + #13#10 + Produtos.ParaTexto; 
end; 

end. 

файл класса «TConversao» - как я это вижу:

unit Conversao; 

interface 

uses 
    Funcao; 

type 
    TConversao = class 
    published 
    function ParaTexto(Funcao: TFuncao): string; 
    end; 

implementation 

uses 
    Solicitacao, 
    Solicitacao.Venda, 
    Funcoes; 

function ParaTexto(Funcao: TFuncao): string; 
begin 
    Result := ''; 

    if (Funcao is TSolicitacao) then 
    Result := 
     Copy(CompletarComEspacoAEsquerda((Funcao as TSolicitacao).SEQUENC, 4), 1, 4) + 
     Completar0AEsquerda(IntToStr(Integer((Funcao as TSolicitacao).FUNCAO)), 2); 

    if (Funcao is TVendaSolicitacao) then 
    begin 
    Result := 
     inherited + 
     Completar0AEsquerda((Funcao as TVendaSolicitacao).NUMPDV, 4) + 
     Completar0AEsquerda((Funcao as TVendaSolicitacao).NUMFISCAL, 6) + 
     Completar0AEsquerda((Funcao as TVendaSolicitacao).AUTORIZ, 12) + 
     IntToStr((Funcao as TVendaSolicitacao).CONV_TIPO); 

    if Produtos.Count > 0 then 
     Result := Result + #13#10 + Produtos.ParaTexto; 
    end; 
+0

Если я правильно понимаю, то, что вы называете «детьми», обычно называют потомками, а то, что вы называете родителем, является «предком». Пожалуйста, исправьте это, это две разные концепции, очень запутывающие. –

+0

@whosrdaddy Я поставил код, например, и конкретное приложение того, что я прошу. –

+0

@whosrdaddy Теперь я вижу, спасибо за отзыв –

ответ

1

Да, вы должны держать этот метод, на этом пути код гораздо более удобным для чтения и повторного использования. Скажем, вы определили нового потомка TSolicitacao, вы переопределите ParaTexto и все. Все изменения находятся в одном месте - в определении вашего класса.

Вы также можете попробовать использовать RTTI для перебора всех свойств класса и создания строки автоматически.

UPDATE

Некоторые советы, как вы можете использовать RTTI (рабочий пример).Вы определяете различные типы чисел:

T7digitsInt = type Int64; 
    T8digitsInt = type Int64; 

Кроме того, тип функции для преобразования из Int64 в строку:

TConvertCustomIntToStringProc = function (num: Int64): string; 

Некоторые испытания класса, которые имеют свойства, что-то вроде вашего TSolicitacao:

TEntry = class (TObject) 
    private 
     fPlainInt: Int64; 
     f7digitInt: T7digitsInt; 
     fWriteOnlyInt: T7digitsInt; 
     f8digitInt: T8digitsInt; 
    published 
     property PlainInt: Int64 read fPlainInt write fPlainInt; 
     property NotSoPlainInt: T7digitsInt read f7digitInt write f7digitInt; 
     property AnotherInt: T7digitsInt write fWriteOnlyInt; 
     property Biggest: T8digitsInt read f8digitInt write f8digitInt; 
    end; 

Также мы объявляем глобальную переменную в нашем подразделении, это список различных типов собственности:

var PropertyConverters: TDictionary<string, TConvertCustomIntToStringProc>; 

Теперь в разделе реализации мы определим некоторые функции, которые преобразуют число в строку:

function ShowPlainInt64(num: Int64): string; 
begin 
    Result:=IntToStr(num); 
end; 

function Show7digitsInt(num: Int64): string; 
begin 
    Result:=Format('%.7d',[num]); 
end; 

Мы «регистрация» это функции для обработки Int64 и T7DigitsInt соответственно, где-то в инициализации, например, в TForm1.create:

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    PropertyConverters:=TDictionary<string, ConvertCustomIntToStringProc>.Create; 
    PropertyConverters.Add('Int64',ShowPlainInt64); 
    PropertyConverters.Add('T7digitsInt',Show7DigitsInt); 
end; 

в TForm1.FormShow мы создаем экземпляр TEntry и заполнить его значения, чтобы проверить наш конвертор, а затем попытаться получить доступ к ним, перебирая свойства:

procedure TForm1.FormShow(Sender: TObject); 
var entry: TEntry; 
    ctx : TRttiContext; 
    rt : TRttiType; 
    prop : TRttiProperty; 
    convertProc: TConvertCustomIntToStringProc; 
begin 
    entry:=TEntry.Create; 
    entry.PlainInt:=12; 
    entry.NotSoPlainInt:=34; 

    //iterating through all the properties with RTTI 
    ctx := TRttiContext.Create(); 
    try 
     rt := ctx.GetType(entry.ClassType); 

     for prop in rt.GetProperties() do begin 
      if prop.IsReadable then 
      if PropertyConverters.TryGetValue(prop.PropertyType.Name,convertProc) then 
       Memo1.Lines.Add(prop.Name+'='+convertProc(prop.GetValue(entry).AsOrdinal)) 
      else 
       Memo1.lines.Add(prop.Name+':unregistered type') 
      else 
      Memo1.Lines.Add(prop.Name+':write-only'); 



     end; 
    finally 
     ctx.Free(); 
    end; 

end; 

Вот что я получил:

PlainInt=12 
NotSoPlainInt=0000034 
AnotherInt:write-only 
Biggest:unregistered type 

Как вы видите, у нас есть несколько целых чисел, они просто имеют другой тип, и мы сделали их показать по-разному из-за этого. Если не так много типов, то такой код может быть очень эффективным.

+0

Да, это более читаемо и многоразово. Когда я подумал над этой идеей, я сосредоточился на концепции типа класса модели и оставил эти классы только с информацией, так как она будет использоваться во всей системе, и будет немного раз, когда этот метод понадобится. Я не использовал RTTI, потому что свойства нужно преобразовать определенным образом, например: CONV_CODIGO необходимо преобразовать в строку с 7 символами и «0» (ноль) слева, если ее размер отличается от 7 , а не просто преобразование. –

+0

Вы можете определить несколько типов синонимов для Integer, как это сделано, например, для TColor, а затем определить разные правила, как их показать, поэтому, если существует не так много разных правил, вы сможете автоматически собирать свойства в одну строку. Инспектор объектов Delphi дает некоторое представление о том, что вы можете сделать с RTTI. Например, FileName - это не что иное, как просто строка, но это другой тип с привязкой правила, как показать и изменить его. Но, конечно, запись каждого ParaTexto вручную является наиболее гибкой. –

+0

Поле будет иметь собственный класс, и в этом классе это будет его метод ParaTexto? Идея, которая у меня была: я думал о создании типа класса с порядком поля один файл, его длину и его процесс для преобразования из любого типа в строку (указатель на функцию или что-то подобное). Но для сохранения этой структуры потребуется больше времени и средств, и в какой-то момент мне нужно будет создать каждое поле и указать его положение, размер и функцию. –