In the code of the company's original system, I saw a lot of codes that distinguish the ClassName attributes of the discriminating objects are processed separately. And it seems to be the standard way to deal with similar problems. But there may be some problems.
First of all, we know that polymorphism is one of the three major features of object-oriented. The so-called polymorphism is that for different concrete types, we can access them through the same abstract interface without having to relate to the implementation details of the concrete types. Just like issuing a notice: all employees gather in People's Square at 9 o'clock tomorrow. It is not necessary to specifically notify each person living in a different location on what time to set out and what route to take, because this is the responsibility of the specific person, not the responsibility of the person who notify the issuer. Therefore, when writing to determine that ClassName needs to be processed separately, the first way to think of is to add an interface to the parent class and complete it through the subclass override. Change the size of the figure as follows:
for i := 0 to Graphic List.Count - 1 do
Begin
Graphics:= Graphic list [i];
if graphic.ClassName = 'rectangle' then
Begin
Rectangle (graphic).Length:= Rectangle (graphic).Length* 2;
Rectangle (graphic).Width:= Rectangle (graphic).Width* 2;
end
else if graph.ClassName = 'Circle' then
Begin
Circle (graphic). Radius:= rectangle (graphic). Radius* 2;
end
end;
You can add the "ChangeSize" method to the parent class "Graphics", the code is as follows
Graphics = class
...
PRocedure ChangeSize(rate: Integer); virtual;
end;
rectangle = class
...
procedure ChangeSize(rate: Integer); override;
end;
Circle = class
...
procedure ChangeSize(rate: Integer); override;
end;
Code to implement size changes in specific graphics classes:
procedure rectangle.ChangeSize(rate: Integer);
Begin
long:= long* rate;
Width:= Width* rate;
end;
procedure Circular.ChangeSize(rate: Integer);
Begin
Radius:= Radius* rate;
end;
After modifying this way, the above code can be called like this:
for i := 0 to Graphic List.Count - 1 do
Begin
Graphics:= Graphic list [i];
Graphics.ChangeSize(2);
end;
This makes the code more clear.
Of course, in many cases, the above solution cannot be used when judging ClassName. For example, iterate over Form's Cotrols and conduct initial trials on different controls. It is impossible for us to add initialization methods to TControl, we can only use to distinguish specific subclass types. Then at this time I recommend using the is operator instead of directly comparing ClassName.
The usage of is, the statement aObject is TForm result in different types of aObject:
aObject is TObject, and the result is false;
aObject is TForm, and the result is true;
aObject is TForm1, and the result is true;
aObject is TEdit, and the result is false;
aObject is nil, and the result is false;
From the above example, we can see an advantage of using is. I can determine whether it is a subclass. For example, when we initialize the control, we use is to judge the process based on whether it is TImage or TEdit. In the future, TCoolEdit may be used to beautify the interface, so this code does not need to be changed, because a TCoolEdit is a TEdit; if ClassName is used, it must be changed to the name of the subclass.
Secondly, if the judged object may be empty, use ClassName to determine whether the object is assigned first, otherwise a memory access error will occur. The judgment representative must be written as: if Assigned(aObject) and aObject.ClassName = 'TClass1'; while using is only written as if aObject is TClass1.
The last reason why ClassName is not used as a judgment is that ClassName is only used to describe the properties of a class. String comparison cannot be checked during the compilation period. If there is a spelling error or a case problem, the code will have logical errors. This An error will only be discovered when the statement is running during the run.
if aControl.ClassName = 'TEidt' then//This code will only be checked if you notice that Edit is not initially tested;
if aControl is TEidt then //Cannot be compiled and passed;
Based on the above, when it is necessary to determine the specific type of an object, first of all, we should consider avoiding such special processing statements through polymorphic processing. If it is really unavoidable, we should use the is operator to judge, rather than ClassName.
In a very special case, is may not get the desired result, such as if TEdit and TCoolEdit need to be handled separately. If it is used, CoolEdit will also be judged as TEdit. At this time, you can use the ClassType method, which will be better than none. Comparison of strings for type detection:
aCoolEdit is TEdit //True;
aCoolEdit.ClassType = TEdit //False;
aCoolEdit.ClassType = TCoolEdit //True;