This question already has answers here:
What does it mean to "program to an interface"?
(33 answers)
Closed 2 years ago.
It's good to code with interface, but does it's a good practice to have method that return interface ?
function CallWebService; IWebServiceReturn;
With that I don't need to free the result of the method and guard from memory leak.
Some people say it's useless, need to be keep for service, and generate more code (a unit for interface, a unit for implementation) than just have a class (or a record) :
function CallWebService; TWebServiceReturn;
For exemple I can have this interface, use to all my result method :
IReturn = interface
procedure GetResult : boolean;
function SetResult(aResult: boolean);
property Result: boolean read GetResult write SetResult;
end;
That I use like that :
var
Return: IReturn;
begin
Result := ProcessMessage(CurrentMessage);
// ...
And in a special call I may need to have more data in the result, so I will create a new interface :
IWebServiceReturn = interface(IReturn)
procedure GetJson : string;
function SetJson(aJson: string);
property Json: string read GetJson write SetJson;
end;
That I will use like that :
var
Return: IWebServiceReturn;
begin
Result := CallWebService(Path);
// ...
And if later, a new call need to get something else I will too create an interface and the class implementation.
That's on this point that we don't have the same opinion on the team.
Some developer see that like a waste of time which will complicate the code.
Apparently they prefer to do something like that :
function CallWebService(Path: string; var Json: string): boolean;
And if you want more data you need to change the method signature..
Too less couple the code I think it's better that always use record or class, this abstraction is necessary if we want to create SOLID code.
I think it's the correct approach when a method can return different implementations, like in the factory design pattern.
Related
With the aim of reducing testing and repeating code I have discovered the multiple inheritance via generic mix-in but I don't know how is the best way to achieve that, as well as best practices.
Having the following class hierarchy example (done with diagrams.net):
This is the spec of the generic:
generic
type S is abstract tagged private;
package GenericChild is
type GenericChild_T is abstract new S with private;
procedure P_SetGenericAttribute (Self : in out GenericChild_T;
i : Integer);
function F_GetGenericAttribute (Self : GenericChild_T)
return Integer;
private
type GenericChild_T is abstract new S with
record
GenericAttribute : Integer;
end record;
end GenericChild;
For the generic instantiation in Child1:
with Root;
with GenericChild;
package Child1 is
type Child1_T is new Root.Root_T with private;
private
package Child1_G is new GenericChild (Root.Root_T);
type Child1_T is new Child1_G.GenericChild_T with null record;
end package Child1;
I can use the methods defined on the Root_T class without problems but, when I try to use the generic methods that is what I get:
no selector "P_SetGenericAttribute" for private type "Child1_T" ...
This is the main.adb where I have tested that:
with Child1;
procedure Main is
Instance : Child1.Child1_T;
begin
Instance.P_SetRootAttribute(1); --ok
Instance.P_SetGenericAttribute(1); --illegal
end main;
Why? Because I have encapsulated the generic package instantiation?
In that case, how is the best way to solve it? Creating public methods in the child classes and calling the private generic instantiation methods within the method implementation? Because I would like to keep the generic instantiation as private. By doing this I'm able to set and get the attribute of the generic.
These are the changes performed to child1.ads that works for me:
with Root;
with GenericChild;
package Child1 is
type Child1_T is new Root.Root_T with private;
procedure P_SetGenericAttribute (Self : in out Child1_T;
i : Integer);
function F_GetGenericAttribute (Self : Child1_T)
return Integer;
private
package Child1_G is new GenericChild (Root.Root_T);
type Child1_T is new Child1_G.GenericChild_T with null record;
end package Child1;
And this is the child1.adb that completes it and works, but I'm not sure if it is a better way to achieve it, such as renaming or something else:
package body Child1 is
procedure P_SetGenericAttribute (Self : in out Child1_T;
i : Integer) is
begin
Child1_G.GenericChild_T(Self).P_SetGenericAttribute (i);
end P_SetGenericAttribute;
function F_GetGenericAttribute (Self : Child1_T)
return Integer is
i : Integer;
begin
i := Child1_G.GenericChild_T(Self).F_GetGenericAttribute;
return i;
end F_GetGenericAttribute;
end package Child1;
Any advice and/or best practices are welcome.
no selector "P_SetGenericAttribute" for private type "Child1_T" ...
The reason you're getting this error is because your implementation (the derivation of the instantiation of GenericChild) is private; your client simply cannot see that the type is such a derivation.
But you have a bigger problem: Ada does not do multiple inheritance like you diagram. You could do multiple interface-types and derive from that, though. OR you could possibly use generic and static polymorphism. -- But straight-up multiple inheritance won't work. (You can, as you mentioned, use mix-ins as well, but those aren't really inheritance.)
This question already has answers here:
How to create an instance of anonymous class of abstract class in Kotlin?
(2 answers)
Closed 2 years ago.
In C# I can:
var a = new { prop42 = "42" };
Console.WriteLine("a.prop42 = " + a.prop42);
Or do some other things, like serialization anonymous class instances (for using in js in browser). No interfaces or abstract classes used, fully anonymous class instance.
It is possible to make same thing in Kotlin?
Yes, you can do the equivalent in Kotlin:
val a = object { val prop42 = "42" }
println("a.prop42 = ${a.prop42}")
It's described in the language reference. See also this question.
This isn't often a good idea, though. Because the type doesn't have a name, you can't use it in public declarations, such as class or top-level properties of that type; nor can you create lists or maps of it. (In general, you can only refer to its named superclass — Any in this case, since you didn't specify one.) So its use is a bit restricted. (The lack of a name also makes the code harder to follow.)
I was studying the object oriented concepts and there the abstraction concept is basically described as hiding the implementation from user. So if there is a member function in a class and we call that function for some task, abstraction says that user should not be concerned about how things are getting done but should only be aware of what is getting done. But even in a non object oriented programming style, if we write a function, the whole task is accomplished by simply calling a function. Doesn't it follow the abstraction logic too? Or, is there any difference between the abstraction in OOP and functional programming?
In Object Oriented Programming, we generally think about Abstractions in terms of inheritance and polymorphism.
Let's consider the Writer interface
interface Writer {
void write(byte[] bytes)
}
This interface allows a user to write to... something. What, we're not particularly worried about. We could have multiple versions of this:
class FileWriter implements Writer
class StringWriter implements Writer
class LogWriter implements Writer
class MySuperCustomWriter implements Writer
Where we write isn't important, be it a File, String, a socket, or wherever. All we want to do is write to something. This lets us write code like this:
public class MyBusinessLogic {
private final Writer writer;
public MyBusinessLogic(Writer writer) {
this.writer = writer;
}
void someBusinessLogic() {
// ..
writer.write(someStuff);
}
}
What we have here is some business logic that wants to do some writing. By using an interface, our business logic is no longer dependent on any specific method of writing. It just gets some object that is capable of doing some writing. We can pass it any of our example writers and be sure that it'll work right, because we're interested here in the behavior of writing, and not the implementation.
By doing this, the business logic is not dependent on the file system, network, or anything else.
It's not the fact that you call a function that is providing the abstraction but the manor in which it's called. For example, you might have a function which allows you to write a line of text:
void writeLine(string fileName, string value)
But that is not abstracted from the fact that you're writing to a file. The abstracted version would not require the caller to provide the fileName parameter because that is specific to that particular implementation of the function. Instead you would have:
void writeLine(string value)
And the fileName is provided using another mechanism e.g. a constructor argument of a class if you're using OOP and calling a writeLine method or, in the functional case, you might curry the original function to create the abstracted version.
Quick Encapsulation Example
type
public class DateTimeClass
private
Era: integer;
Culture: integer;
Year: integer;
Month: integer;
Day: integer;
protected
Integer function getYear ( );
// other functions
procedure setYear ( );
// other functions
public
procedure AssignOccidentalDate
(NewYear: integer; NewMonth: integer;
NewDay : integer);
end;
...
var Date: DateTimeClass;
Date.AssignOccidentalDate (2019, 07, 27);
...
You can only access the "public" declarations.
I wonder what prefix you guys use for methods that create or calculate a value based on given parameters. I tend to use "get", but that feels wrong, because it looks like a getter then.
For methods that fetch from the database I use "fetch", but for methods that create a value based on the given input I haven't found a satisfying prefix yet. ("create" feels a bit too generic). Are there guidelines for this or is everyone just thinking up something for themselves?
Pseudo code example:
class myClass
{
method getOrderFlowpoint(par1, par2, par3) {
// do stuff based on the parameters
return orderFlowpoint;
}
}
I tend to not use prefixes. I tend to name the method according to the exact function it fulfills.
If your function calculates the order flowpoint, that's exactly how you should name it. calculateOrderFlowpoint.
If your class is only about OrderFlowPoints, I have seen the following, all linked to the Factory Pattern:
OrderFlowPoint.of(par1, par2, par3);
OrderFlowPoint.valueOf(par1, par2, par3);
OrderFlowPoint.newInstance(par1, par2, par3);
Is it possible to serialize a TCollection which is not encapsulated in a TComponent ?
For example, I have a custom TCollection. I can't use TMemoryStream.WriteComponent() on my TCollection descendant. It'll only works if I encapsulate the collection in a TComponent and then if I write this component.
Technically there is no problem but declaring a TComponent which only owns a TCollection seems a bit odd.
TMyCustomCollection = Class(TCollection) // not serializable ?
//...
End;
TMyCustomCollectionCapsule = Class(TComponent) // serializable !
Private
FMyCusColl: TMyCustomCollection;
Procedure SetMyCusColl(Const Data: TMyCustomCollection);
Published
Property CanBeSerialized: TMyCustomCollection Read FMyCusColl Write SetMyCusColl
End;
Maybe I just miss a feature of the Delphi RTL? Can a TPersistent descendent be streamed without being itself encapsulated in a TComponent ?
It only works if you put your collection in a TComponent, because TMemoryStream.WriteComponent (the name itself is a clue!) takes a TComponent as a parameter:
procedure WriteComponent(Instance: TComponent);
and TCollection is as you already discovered not a TComponent descendant. It may seem odd to have a TComponent descendant just to hold your TCollection descendant, but if you want to stream it using the WriteComponent facilities of streams, I don't see any other easy way to do it.
If you want to do this using "just" the RTL/VCL (ie not using a third party library), you would have to write a T(Memory)Stream descendant and add a WritePersistent implementation that takes an Instance: TPersistent parameter.
I haven't delpheddelved into the TStream classes that much, but my guess is that you w/should be able to borrow a lot from the TComponent support. Certainly the class inheritance support.
Having had a cursory look, it seems simple at first as WriteComponent just calls WriteDescendent which instantiates a TWriter and then calls the WriteDescendent method of that writer. And the TWriter already contains methods to write a collection.
However, if you "just" want to stream TPersistent descendants, you will have to do a lot of work in TWriter/TReader as well as they are completely based around TComponent. And it won't be a simple case of just writing a couple of descendant. For one, they TWriter/TReader are not really set up to be derived from. For another: TStream (descendants) instantiate TWriter and TReader directly and these classes do not have virtual constructors. Which makes writing descendants for them fairly futile unless you would like to try your hand at hooking, patching the VMT and more of that interesting stuff.
All in all: the easiest way to stream your custom collection remains to "just" wrap it in a TComponent and live with the "waste" of that.
You can serialize a TCollection not encapsuled within a TComponent by means of another TComponent descendant defined as follows:
type
TCollectionSerializer = class(TComponent)
protected
FCollectionData: string;
procedure DefineProperties(Filer: TFiler); override;
public
procedure WriteData(Stream: TStream);
procedure ReadData(Stream: TStream);
//
procedure LoadFromCollection(ACollection: TCollection);
procedure SaveToCollection(ACollection: TCollection);
end;
DefineProperties, WriteData and ReadData implementation details:
procedure TCollectionSerializer.WriteData(Stream: TStream);
var
StrStream: TStringStream;
begin
StrStream:=TStringStream.Create;
try
StrStream.WriteString(FCollectionData);
Stream.CopyFrom(StrStream,0);
finally
StrStream.Free;
end;
end;
procedure TCollectionSerializer.ReadData(Stream: TStream);
var
StrStream: TStringStream;
begin
StrStream:=TStringStream.Create;
try
StrStream.CopyFrom(Stream,0);
FCollectionData:=StrStream.DataString;
finally
StrStream.Free;
end;
end;
procedure TCollectionSerializer.DefineProperties(Filer: TFiler);
begin
inherited;
//
Filer.DefineBinaryProperty('CollectionData', ReadData, WriteData,True);
end;
Templates of LoadFromCollection and SaveToCollection:
procedure TCollectionSerializer.LoadFromCollection(ACollection: TCollection);
var
CollectionStream: TStream;
begin
CollectionStream:= TCollectionStream.Create(ACollection);
try
ReadData(CollectionStream)
finally
CollectionStream.Free;
end;
end;
procedure TCollectionSerializer.SaveToCollection(ACollection: TCollection);
var
CollectionStream: TStream;
begin
CollectionStream:= TCollectionStream.Create(ACollection);
try
WriteData(CollectionStream);
finally
CollectionStream.Free;
end;
end;
About TCollectionStream:
It should be a TStream descendant having a rich creator with a TCollection as a parameter and designed to behave like a TFileStream. You must implement it. Disclaimer: I have never tested that but I can tell that a TFileStream works (for streaming external file).
Conclusion:
This component is inspired by the VCL way to serialize within a DFM an external file under Delphi XE (RCData). It must be registred along with a component editor (that you must also implement based on TComponentEditor) doing the serialization at designtime.