@Mike Warren All the feedback above is valid, but will add more comments...
Just a comment on your interface where you flagged an error:
IapShape = interface
procedure SetThing(AThing: Boolean);
function GetThing : boolean; // this is what was missing
property Thing: Boolean read GetThing write SetThing;
end;
TapRectangle = class(TRectangle, IapShape) // If you want reference counting, TRectangle should inherit from TInterfacedObject, or else, you need to add the ref counting methods somewhere like TRectangle or here...
private
FThing: Boolean;
function GetThing : boolean; // this can be as trivial as: result := FThing;
procedure SetThing(AThing: Boolean);
public
property Thing: Boolean read FThing write SetThing; // this can actually be different to the interface, but ideally, to be consistent, it should be identical to ensure consistent behaviour
end;
Hope the comments help. It is possible to have a class implement multiple interfaces, and then in code, you can use methods like supports() to check if an interface supports other interfaces... Anyways, as Arnaud mentioned, composition is generally better, but depending on the scenario, having class/interface hierarchies have their uses.... Having a collection of shapes is a scenario which consist of a rectangles, circles, etc, benefits form the inheritance scenario you described, so if there are generic methods that take place on the shape, it may make sense... e.g. shape.draw, shape.area, shape.position ... but to get to the specific details of a shape, much as with classes, you can get an interface specific to the specialisation (TRectangle, IRectangle...)
Anyways, the design topic is vast, and can be very opionated as well 😉
My suggestion in line with Arnaud is something like:
in the above, your TRectangle or TCircle would be contained in the FShape field