问题
This is a follow up of my earlier post here:
Ada: Understanding private types and understanding packaging
An implementation for the Rectangular
type was made using one implementation i.e. Rectangular_Method_1
and a specification file and a body file were required for this implementation.
If we want to have another implementation Rectangular_Method_2
available to the user then the main file rectangular_Form.ads
can be changed to
-- with Rectangular_Method_1;
-- package Rectangular_Form renames Rectangular_Method_1;
with Rectangular_Method_2;
package Rectangular_Form renames Rectangular_Method_2;
Questions
Is this the right way in software engineering to allow for another implementation in that the test file
test_rectangular_form.adb
remains the same for a different implementation?If we create a second implementation
Rectangular_Method_2
, Is there a need to create a separate specification file in addition to the compulsory new body for this new implementation? There is the need however to provide the same procedures/functions forVector_Basis_r
,Set_Horz
,Get_Horz
etc in the new implementation so that we can call them intest_rectangular_form.adb
.
Thanks...
回答1:
If you use GNAT, you can use GPR files for the project. In there you can change the filename for specific packages, for example:
for Specification (Rectangular_Form) use "Rectangular_Method_1.ads";
for Implementation (Rectangular_Form) use "Rectangular_Method_1.adb";
you can even set this depending on an environment variable.
If your spec files all should look the same, you can use a Rectangular_Form.ads
and only use the Implementation line from above.
An example GPR file could look like this:
project Example is
type Methods is ("normal", "something_else");
Method : Methods := external ("METHOD", "normal");
package Naming is
case Method is
when "normal" =>
for Implementation ("Example") use "example_normal.adb";
when "something_else" =>
for Implementation ("Example") use "example_something.adb";
end case;
end Naming;
end Example;
Then, you can use gnatmake -P example.gpr
to compile it depending on your METHOD
variable, or using a -XMETHOD=...
parameter for gnatmake or just use the provided default value.
The example_*.adb
should all contain the body of the package Example
, not Example_Normal
, etc..
回答2:
Another way to do this would be to use tagged types.
package Rectangular is
type Instance is abstract tagged private;
procedure Vector_Basis_r (A : in Long_Float; D : out Instance);
procedure Set_Horz (R : in out Instance; H : Long_Float);
function Get_Horz (R : Instance) return Long_Float;
private
type instance is tagged null record;
end Rectangular;
with Rectangular;
package Rectangular_Method_1 is
type Instance is new Rectangular.Instance with private;
...
private
type Instance is new Rectangular.Instance with
record
Horz, Vert: Long_Float;
end record;
end Rectangular_Method_1;
(similar implementation for Rectangular_Method_2).
Then I believe you can write your code that uses it this way:
with Rectangular_Method_1;
with Rectangular_Method_2;
...
-- My_Rectangle : Rectangular_Method_1.Instance;
My_Rectangle : Rectangular_Method_2.Instance;
My_Rectangle.Set_Horiz(Whatever_Value);
...
In other words, all you'd have to change when switching between the two is the type names. Your client could even get rid of those changes by using a single subtype at the top.
subtype Rectangle_Instance is Rectangular_Method_2.Instance;
This would also give you the ability to move common code/fields up into the base class (package), which I think is sort of what you were after.
来源:https://stackoverflow.com/questions/10408459/ada-packaging-concepts