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.
Комментариев нет:
Отправить комментарий