Original in Russian: http://programmingmindstream.blogspot.ru/2015/09/1159-record.html
By no means always class members paradigm private/protected/public works as we would like it to work.
In fact, class may have “ordinary” users, “advanced” users and “experts” .
Sometimes we want to provide each class of users with its "own level of access" to design class methods.
I devoted much thought to the ways how to do it.
Sure, interfaces may be used. I would not tell how for I believe you know it well.
But (!) interfaces are the overhead to AddRef/Release.
Sometimes we try to avoid this overhead.
We try to make something similar to interfaces that has no ARC. I dare say, "the protocols”.
Here are the links about the “protocols”:
Protocols vs interfaces. (in Russian)
"Makeshift" protocols. (in Russian)
Objective-C and Delphi.
Wide use of interfaces “in general” and InterlockedIncrement/InterlockedDecrement in particular…
(in Russian)
I don't know how "methods are called by name" in Objective-C, but that's how I would do it … (in Russian)
These are all “cows a in vacuum”.
How can we achieve it in practice?
I have been thinking it over and over again and came up with the following staff.
Nothing extraordinary. We simply make “facade" records that have access to the “object’s intestine”.
This is similar to Enumerators that are also implemented by records:
Generics, "mixins", interfaces and enumerators - just the code (in Russian)
With reference to my mate's words, "thoughts about syntax sugar" (in Russian)
Something as follows:
https://bitbucket.org/lulinalex/mindstream/src/b550da2431d733e50aab7b5bb3c4dcca7f3f68aa/Examples/Protocols/Protocols.dpr?at=B284&fileviewer=file-view-default
That is all...
Of course, it is mundane and not wise to repeat it “for each class”.
However, it is useful in case of a “complex” class that has more than one "responsibility".
I do know about KISS and SRP.
(+) I do also know about RTTI and helpers.
(+)(+) Sure, I do know about God-object, too.
By no means always class members paradigm private/protected/public works as we would like it to work.
In fact, class may have “ordinary” users, “advanced” users and “experts” .
Sometimes we want to provide each class of users with its "own level of access" to design class methods.
I devoted much thought to the ways how to do it.
Sure, interfaces may be used. I would not tell how for I believe you know it well.
But (!) interfaces are the overhead to AddRef/Release.
Sometimes we try to avoid this overhead.
We try to make something similar to interfaces that has no ARC. I dare say, "the protocols”.
Here are the links about the “protocols”:
Protocols vs interfaces. (in Russian)
"Makeshift" protocols. (in Russian)
Objective-C and Delphi.
Wide use of interfaces “in general” and InterlockedIncrement/InterlockedDecrement in particular…
(in Russian)
I don't know how "methods are called by name" in Objective-C, but that's how I would do it … (in Russian)
These are all “cows a in vacuum”.
How can we achieve it in practice?
I have been thinking it over and over again and came up with the following staff.
Nothing extraordinary. We simply make “facade" records that have access to the “object’s intestine”.
This is similar to Enumerators that are also implemented by records:
Generics, "mixins", interfaces and enumerators - just the code (in Russian)
With reference to my mate's words, "thoughts about syntax sugar" (in Russian)
Something as follows:
https://bitbucket.org/lulinalex/mindstream/src/b550da2431d733e50aab7b5bb3c4dcca7f3f68aa/Examples/Protocols/Protocols.dpr?at=B284&fileviewer=file-view-default
program Protocols;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
TmyClass = class
public
// Here come the protocols for “advanced” user:
type
Advanced1 = record
private
f_Provider : TmyClass;
public
constructor Create(aProvider: TmyClass);
procedure ForAdvancedUser1;
procedure ForAdvancedUser2;
end;//Advanced1
Advanced2 = record
private
f_Provider : TmyClass;
public
constructor Create(aProvider: TmyClass);
procedure ForAdvancedUser1;
end;//Advanced2
Advanced3 = record
private
f_Provider : TmyClass;
public
constructor Create(aProvider: TmyClass);
procedure ForAdvancedUser2;
end;//Advanced3
// Here come the protocols for “experts”:
type
Expert1 = record
private
f_Provider : TmyClass;
public
constructor Create(aProvider: TmyClass);
procedure ForExpertUser1;
procedure ForExpertUser2;
end;//Expert1
Expert2 = record
private
f_Provider : TmyClass;
public
constructor Create(aProvider: TmyClass);
procedure ForExpertUser1;
end;//Expert2
Expert3 = record
private
f_Provider : TmyClass;
public
constructor Create(aProvider: TmyClass);
procedure ForExpertUser2;
end;//Expert3
private
procedure ForAdvancedUser1;
procedure ForAdvancedUser2;
procedure ForExpertUser1;
procedure ForExpertUser2;
public
procedure ForRegularUser1;
procedure ForRegularUser2;
public
// Here come the methods to get the “protocols”
function AsA1: Advanced1;
function AsA2: Advanced2;
function AsA3: Advanced3;
function AsE1: Expert1;
function AsE2: Expert2;
function AsE3: Expert3;
end;//TmyClass
// TmyClass.Advanced1
constructor TmyClass.Advanced1.Create(aProvider: TmyClass);
begin
f_Provider := aProvider;
end;
procedure TmyClass.Advanced1.ForAdvancedUser1;
begin
f_Provider.ForAdvancedUser1;
end;
procedure TmyClass.Advanced1.ForAdvancedUser2;
begin
f_Provider.ForAdvancedUser2;
end;
// TmyClass.Expert1
constructor TmyClass.Expert1.Create(aProvider: TmyClass);
begin
f_Provider := aProvider;
end;
procedure TmyClass.Expert1.ForExpertUser1;
begin
f_Provider.ForExpertUser1;
end;
procedure TmyClass.Expert1.ForExpertUser2;
begin
f_Provider.ForExpertUser2;
end;
// TmyClass.Expert2
constructor TmyClass.Expert2.Create(aProvider: TmyClass);
begin
f_Provider := aProvider;
end;
procedure TmyClass.Expert2.ForExpertUser1;
begin
f_Provider.ForExpertUser1;
end;
// TmyClass.Expert3
constructor TmyClass.Expert3.Create(aProvider: TmyClass);
begin
f_Provider := aProvider;
end;
procedure TmyClass.Expert3.ForExpertUser2;
begin
f_Provider.ForExpertUser2;
end;
// TmyClass.Advanced2
constructor TmyClass.Advanced2.Create(aProvider: TmyClass);
begin
f_Provider := aProvider;
end;
procedure TmyClass.Advanced2.ForAdvancedUser1;
begin
f_Provider.ForAdvancedUser1;
end;
// TmyClass.Advanced3
constructor TmyClass.Advanced3.Create(aProvider: TmyClass);
begin
f_Provider := aProvider;
end;
procedure TmyClass.Advanced3.ForAdvancedUser2;
begin
f_Provider.ForAdvancedUser2;
end;
// TmyClass
procedure TmyClass.ForAdvancedUser1;
begin
WriteLn('ForAdvancedUser1');
end;
procedure TmyClass.ForAdvancedUser2;
begin
WriteLn('ForAdvancedUser2');
end;
procedure TmyClass.ForExpertUser1;
begin
WriteLn('ForExpertUser1');
end;
procedure TmyClass.ForExpertUser2;
begin
WriteLn('ForExpertUser2');
end;
procedure TmyClass.ForRegularUser1;
begin
WriteLn('ForRegularUser1');
end;
procedure TmyClass.ForRegularUser2;
begin
WriteLn('ForRegularUser2');
end;
function TmyClass.AsA1: Advanced1;
begin
Result := Advanced1.Create(Self);
end;
function TmyClass.AsA2: Advanced2;
begin
Result := Advanced2.Create(Self);
end;
function TmyClass.AsA3: Advanced3;
begin
Result := Advanced3.Create(Self);
end;
function TmyClass.AsE1: Expert1;
begin
Result := Expert1.Create(Self);
end;
function TmyClass.AsE2: Expert2;
begin
Result := Expert2.Create(Self);
end;
function TmyClass.AsE3: Expert3;
begin
Result := Expert3.Create(Self);
end;
var
l_C : TmyClass;
begin
try
l_C := TmyClass.Create;
try
l_C.ForRegularUser1;
l_C.ForRegularUser2;
l_C.AsA1.ForAdvancedUser1;
l_C.AsA1.ForAdvancedUser2;
l_C.AsA2.ForAdvancedUser1;
l_C.AsA3.ForAdvancedUser2;
l_C.AsE1.ForExpertUser1;
l_C.AsE1.ForExpertUser2;
l_C.AsE2.ForExpertUser1;
l_C.AsE3.ForExpertUser2;
finally
FreeAndNil(l_C);
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
That is all...
Of course, it is mundane and not wise to repeat it “for each class”.
However, it is useful in case of a “complex” class that has more than one "responsibility".
I do know about KISS and SRP.
(+) I do also know about RTTI and helpers.
(+)(+) Sure, I do know about God-object, too.
Комментариев нет:
Отправить комментарий