2017-02-08 14 views
10

TÌNHCác nhà xây dựng bản ghi Delphi có thực sự cần thiết không?

Tôi đang nghiên cứu "More Mã hóa trong Delphi" Nick Hodges, và ông đang sử dụng một kỷ lục TFraction để giải thích điều hành quá tải. Tôi đã tự viết bản ghi này:

type 
    TFraction = record 
    strict private 
    aNumerator: integer; 
    aDenominator: integer; 
    function GCD(a, b: integer): integer; 
    public 
    constructor Create(aNumerator: integer; aDenominator: integer); 
    procedure Reduce; 
    class operator Add(fraction1, fraction2: TFraction): TFraction; 
    class operator Subtract(fraction1, fraction2: TFraction): TFraction; 
    //... implicit, explicit, multiply... 
    property Numerator: integer read aNumerator; 
    property Denominator: integer read aDenominator; 
    end; 

Tất nhiên, tôi phải tạo một hàm tạo vì trong Q (lý trí) tôi phải có mẫu số không bằng 0.

constructor TFraction.Create(aNumerator, aDenominator: integer); 
begin 
    if (aDenominator = 0) then 
    begin 
    raise Exception.Create('Denominator cannot be zero in rationals!'); 
    end; 

    if ((aNumerator < 0) or (aDenominator < 0)) then 
    begin 
    Self.aNumerator := -aNumerator; 
    Self.aDenominator := -aDenominator; 
    end 
    else 
    begin 
    Self.aNumerator := aNumerator; 
    Self.aDenominator := aDenominator; 
    end; 
end; 

VẤN ĐỀ

Kể từ khi quá tải toán tử trả về một TFraction, tôi sẽ xác định một hoạt động như thế này:

class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction; 
var 
    tmp: TFraction; 
begin 
    //simple algorithm of the sum 
    tmp := TFraction.Create(fraction1.Numerator*fraction2.Denominator+fraction1.Denominator*fraction2.Numerator, fraction1.Denominator*fraction2.Denominator); 
    tmp.Reduce; 

    //return the result 
    Result := tmp; 
end; 

Như bạn có thể thấy ở đây, tôi tạo một tmp được trả về từ hàm.

Khi tôi đọc cuốn sách Marco Cantu, ông đã sử dụng cách tiếp cận khác:

class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction; 
begin 
    Result.aNumerator := (fraction1.Numerator*fraction2.Denominator+fraction1.Denominator*fraction2.Numerator); 
    Result.aDenominator := fraction1.Denominator*fraction2.Denominator; 
end; 

Tôi đã thực hiện một số xét nghiệm, và tôi thấy rằng cả hai cho tôi kết quả chính xác, nhưng có cái gì đó mà tôi không thể hiểu được. Trong phương pháp tiếp cận đầu tiên, tôi tuyên bố tmp và sau đó tôi gọi hàm tạo để tôi có thể trả lại TFraction. Trong phương pháp thứ hai, tôi thay vì không tạo ra bất cứ điều gì vì các bản ghi có một hàm tạo tự động. Các tài liệu, trên thực tế, nói rằng:

Các bản ghi được tạo tự động, sử dụng một đối số mặc định không có đối số , nhưng các lớp phải được xây dựng một cách rõ ràng. Bởi vì các bản ghi có một hàm tạo không có đối số mặc định, bất kỳ người tạo nào được xác định bởi người dùng được định nghĩa thì phải có một hoặc nhiều tham số.

Ở đây tôi có một hàm tạo bản ghi do người dùng xác định. Vì vậy:

  1. Gọi hàm tạo trên tmp cách tiếp cận đầu tiên không cần thiết? Nếu tôi muốn gọi Reduce (đó là một thủ tục), tôi cần phải tạo một biến. Có phải Result chỉ trả về một bản sao của tmp mà không cần tạo bất kỳ thứ gì không?

  2. Trong phương pháp thứ hai, là Result.aNumeratorResult.aDenominator thông số của hàm tạo được tạo tự động?

+0

Trên ghi chú không liên quan, thường là sử dụng 'F' làm tiền tố cho trường riêng tư trong một lớp và tiền tố' A' cho tham số phương pháp (bạn sử dụng). Ở Delphi, nó ổn, nhưng rõ ràng, ở Lazarus, điều đó sẽ không biên dịch được. –

+0

Ok cảm ơn bạn tôi không biết, tôi đang sử dụng một tham số và các biến. Tôi sẽ thay đổi thói quen của mình! –

+0

@Jerry Ý bạn là gì. FPC không thực thi các quy tắc quy ước đặt tên. –

Trả lời

9

Trình tạo bản ghi không phải là điều kỳ diệu. Nó chỉ là một phương pháp dụ như bất kỳ phương pháp nào khác.Bạn viết:

tmp := TFraction.Create(...); 

Nhưng bạn tốt như nhau có thể viết nó như thế này:

tmp.Create(...); 

Cá nhân tôi thấy không phải là đặc biệt hữu ích bởi vì tôi đang sử dụng để xây dựng gọi ngữ nghĩa cho các lớp học mà phân bổ và khởi mặc định bộ nhớ, và sau đó gọi phương thức khởi tạo.

Và đặc biệt là biến thể thứ hai có liên quan đến tôi vì nó trông giống như sai lầm kinh điển mà những người lập trình Delphi mới làm khi bắt đầu và cố tạo một thể hiện của một lớp. Mã đó sẽ không tốt nếu TFraction là một lớp, nhưng đối với một bản ghi thì nó là tốt.

Có phải tôi là tôi sẽ loại bỏ hàm tạo bản ghi và thay vào đó sử dụng hàm lớp tĩnh trả về một bản sao mới được tạo kiểu bản ghi của bạn. Quy ước của tôi là đặt tên những thứ như vậy New. Nhưng đây là những vấn đề sở thích cá nhân.

Nếu bạn đã làm điều đó nó sẽ được khai báo như thế này:

class function New(aNumerator, aDenominator: Integer): TFraction; static; 

Nó sẽ được thực hiện như thế này:

class function TFraction.New(aNumerator, aDenominator: Integer): TFraction; 
begin 
    Result.aNumerator := ...; 
    Result.aDenominator := ...; 
end; 

Sau đó, bạn sẽ gọi nó là như thế này:

frac := TFraction.New(num, denom); 

Nhưng như tôi đã nói, đó là vấn đề ưu tiên. Nếu bạn thích các nhà xây dựng bản ghi, hãy cứ gắn bó với họ.


Bạn hỏi bạn có thể bỏ qua hàm tạo hay không. Về phân bổ hồ sơ, có bạn có thể bỏ qua nó. Về việc chạy mã trong hàm tạo, chỉ có bạn mới có thể xác định điều đó. Bạn có muốn mã đó thực thi hay không?

Nếu bạn muốn rằng mã được thực thi, nhưng không muốn sử dụng một biến tạm thời, sau đó bạn có thể viết mã như thế này:

class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction; 
begin 
    Result.Create(
    fraction1.Numerator*fraction2.Denominator + fraction1.Denominator*fraction2.Numerator, 
    fraction1.Denominator*fraction2.Denominator 
); 
    Result.Reduce; 
end; 

Hoặc nếu bạn ưa thích một chức năng lớp tĩnh nó sẽ là:

class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction; 
begin 
    Result := TFraction.New(
    fraction1.Numerator*fraction2.Denominator + fraction1.Denominator*fraction2.Numerator, 
    fraction1.Denominator*fraction2.Denominator 
); 
    Result.Reduce; 
end; 
+0

Tôi thích cách xây dựng bởi vì nó có vẻ sạch hơn với tôi. Nick đang làm chính xác những gì bạn đang đề xuất với tôi với chức năng lớp học –

+0

Ngoài ra tôi không biết về điều Kết quả. Nó được coi như một biến bình thường? Tôi thấy rằng bạn có thể gọi là Giảm trên nó! –

+3

Các nhà xây dựng IMO trên hồ sơ là gây hiểu lầm (nói chung). Không có cách nào để đảm bảo nó sẽ được sử dụng. Bản ghi là "giá trị", không phải là một đối tượng. –

Các vấn đề liên quan