Так что да, это возможно.
Я настоятельно рекомендую вам не придерживаться этого подхода.У него очень плохие проблемы с производительностью, не говоря уже о том, что его сложнее поддерживать.Это, как говорится, на самом деле возможно (и должно быть на любом языке с отправкой).Это достигается расширением беглого шаблона, в котором используется промежуточный тип, чтобы основной тип оставался доступным только для чтения.Поскольку в Ada нет полей, доступных только для чтения, вам также потребуется использовать шаблон свойств, чтобы поля были доступны только для чтения.
Вот спецификация
with Ada.Strings.Unbounded;
use Ada.Strings.Unbounded;
package Persons is
type Person is tagged private;
function First_Name(Self : in Person) return String;
function Middle_Name(Self : in Person) return String;
function Last_Name(Self : in Person) return String;
function Date_of_Birth(Self : in Person) return String;
function Place_of_Birth(Self : in Person) return String;
type Person_Builder is tagged private;
function Builder return Person_Builder;
function First_Name(Self : in Person_Builder; Value : in String) return Person_Builder;
function Middle_Name(Self : in Person_Builder; Value : in String) return Person_Builder;
function Last_Name(Self : in Person_Builder; Value : in String) return Person_Builder;
function Date_of_Birth(Self : in Person_Builder; Value : in String) return Person_Builder;
function Place_of_Birth(Self : in Person_Builder; Value : in String) return Person_Builder;
function Build(Source : in Person_Builder'Class) return Person;
private
type Person is tagged record
First_Name : Unbounded_String;
Middle_Name : Unbounded_String;
Last_Name : Unbounded_String;
Date_of_Birth: Unbounded_String;
Place_of_Birth: Unbounded_String;
end record;
type Person_Builder is tagged record
First_Name : Unbounded_String;
Middle_Name : Unbounded_String;
Last_Name : Unbounded_String;
Date_of_Birth: Unbounded_String;
Place_of_Birth: Unbounded_String;
end record;
end Persons;
и тело
package body Persons is
function First_Name(Self : in Person) return String is (To_String(Self.First_Name));
function Middle_Name(Self : in Person) return String is (To_String(Self.Middle_Name));
function Last_Name(Self : in Person) return String is (To_String(Self.Last_Name));
function Date_of_Birth(Self : in Person) return String is (To_String(Self.Date_of_Birth));
function Place_of_Birth(Self : in Person) return String is (To_String(Self.Place_of_Birth));
function Builder return Person_Builder is
begin
return Person_Builder'(To_Unbounded_String(""), To_Unbounded_String(""), To_Unbounded_String(""), To_Unbounded_String(""), To_Unbounded_String(""));
end Builder;
function First_Name(Self : in Person_Builder; Value : in String) return Person_Builder is
begin
return Person_Builder'(To_Unbounded_String(Value), Self.Middle_Name, Self.Last_Name, Self.Date_of_Birth, Self.Place_of_Birth);
end First_Name;
function Middle_Name(Self : in Person_Builder; Value : in String) return Person_Builder is
begin
return Person_Builder'(Self.First_Name, To_Unbounded_String(Value), Self.Last_Name, Self.Date_of_Birth, Self.Place_of_Birth);
end Middle_Name;
function Last_Name(Self : in Person_Builder; Value : in String) return Person_Builder is
begin
return Person_Builder'(Self.First_Name, Self.Middle_Name, To_Unbounded_String(Value), Self.Date_of_Birth, Self.Place_of_Birth);
end Last_Name;
function Date_of_Birth(Self : in Person_Builder; Value : in String) return Person_Builder is
begin
return Person_Builder'(Self.First_Name, Self.Middle_Name, Self.Last_Name, To_Unbounded_String(Value), Self.Place_of_Birth);
end Date_of_Birth;
function Place_of_Birth(Self : in Person_Builder; Value : in String) return Person_Builder is
begin
return Person_Builder'(Self.First_Name, Self.Middle_Name, Self.Last_Name, Self.Date_of_Birth, To_Unbounded_String(Value));
end Place_of_Birth;
function Build(Source : in Person_Builder'Class) return Person is
begin
return Person'(Source.First_Name, Source.Middle_Name, Source.Last_Name, Source.Date_of_Birth, Source.Place_of_Birth);
end Build;
end Persons;
Затем пример программы, использующей этот пакет
with Ada.Text_IO, Persons;
use Ada.Text_IO, Persons;
procedure Proof is
P : Person;
begin
P := Builder
.First_Name("Bob")
.Last_Name("Saget")
.Place_of_Birth("Philadelphia, Pennsylvania")
.Build;
Put_Line("Hello, my name is " & P.First_Name & " " & P.Last_Name & " and I am from " & P.Place_of_Birth);
Put_Line("Middle Name: " & P.Middle_Name);
Put_Line("Date of Birth: " & P.Date_of_Birth);
end Proof;
А вот вывод командной строки
Теперьпозволь мне объяснить.Ваш основной тип, конечно, Person
, с Person_Builder
, действующим как изменчивая форма этого.Builder
преобразует из Person
в Person_Builder
и Build
преобразует из Person_Builder
обратно в Person
.Person
поддерживает только доступ только для чтения к полям через шаблон свойств.Точно так же Person_Builder
поддерживает мутацию, но не через шаблон свойства, а через беглый шаблон, который возвращает новый экземпляр при каждом вызове.Эти изменения могут быть затем объединены в цепочку в результате свободного применения.