Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Pattern required

Posted on 2004-11-12
8
Medium Priority
?
151 Views
Last Modified: 2010-04-05
I want to provide myself with a little framework that looks something like:
  A = class
  A1 = class (A)
  A2 = class(A)
A1 and A2 are still abstract and I have to derive some Bs from either A1 or A2. A1 and A2 implement a method Foo that I want to call from A but I don’t want any B to be able to override Foo. I know I can put A, A1 and A2 into one single file and access private methods but I want to avoid it (I like small units). Tricky?
0
Comment
Question by:__alex
  • 4
  • 2
  • 2
8 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12564132
If A1 and A2 implement new functions that are not defined as abstract in A then A will not be able to call them. If you define function Foo in A as virtual and abstract then any class that inherits from A will be able to override the Foo method.

As an alternative, consider using interfaces instead. An interface is like an object with no data fields and only abstract methods. Thus you would get:

type
  A = interface
    procedure Foo;
  end;
  A1 = class( TInterfacedObject, A )
    procedure Foo;
  end;
  A2 = class( TInterfacedObject, A )
    procedure Foo;
  end;
  B = class( TInterfacedObject, A )
    FA: A;
    constructor Create( Foo: A );
    property ImplementFoo: A read FA write FA implements A;
  end;

procedure A1.Foo;
begin
  MessageBox( GetDesktopWindow, 'A1', 'A1', MB_OK );
end;

procedure A2.Foo;
begin
  MessageBox( GetDesktopWindow, 'A2', 'A2', MB_OK );
end;

constructor B.Create( Foo: A );
begin
  inherited Create;
  ImplementFoo := Foo;
end;

procedure CallFoo;
var
  FooB: A;
begin
  FooB := B.Create( A1.Create );
  FooB.Foo;
  FooB := B.Create( A2.Create );
  FooB.Foo;
end;

See, the methods aren't even virtual! :-)
Now, the fun part is that B can use any class that supports the A interface. (Thus, even itself!) But B is NOT able to overwrite the Foo method in whatever interface that is passed to it.
Interfaces don't really add much overhead either. We're talking about a few bytes of overhead. Then again, if you want B to only support the Foo method of class A2 then use this instead:

  B = class( TInterfacedObject, A )
    FA: A2;
    constructor Create( Foo: A2 );
    destructor Destroy; override;
    property ImplementFoo: A2 read FA write FA implements A;
  end;

Remember though that you need a destructor now to free the class that is now linked to your class.

Working with interfaces is difficult at first, but extremely useful for using patterns.
0
 
LVL 2

Author Comment

by:__alex
ID: 12564503
Nice, but...
The only reason for A1 and A2 being derived from A is because I want to reuse code. It’s not the kind of A1/A2-is-an-A relationship, semantically speaking. If I’ll go for interfaces like your approach implementation is shifted from A to A1/A2. My actual workaround is a procedural type property fnFoo in A that can be set only once. It is set in the constructor of A1 or A2. => A can call fnFoo but Bs can’t alter it. But as I said, it’s just a workaround.
0
 
LVL 17

Accepted Solution

by:
Wim ten Brink earned 800 total points
ID: 12564560
Well, that would not be a big problem. In my code, I inherited A1 and A2 from class TInterfacedObject but you could just as well create a class A and an interface called InterfaceA, if you like. The interface would limit the override of the Foo method.

Thus:

type
  AInterface = interface;
  A = class;
  A1 = Class(A, AInterface);
  A2 = Class(A, AInterface);
  B = Class(A, AInterface)
    FA: AInterface;
    property ImplementFoo: AInterface read FA write FA implements AInterface;
  end;

I like interfaces, btw. The garbage collector will free them once they're not in use anymore. Furthermore, they allow a better kind of polymorphism, making very different classes seem very similar. And it allows you to make your code look more abstract. You do have to get used to them but once you know how you can use them, they're almost addictive.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12571012
Hi Alex,

I don't understand your interface thingy above... why do A1 and A2 have to declare the code for Foo whereas B doesn't? Since B uses the A interface as well...
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12576389
B doesn't have to implement the Foo method since the implementation fo the interface is passed onwards to the ImplementFoo property. You assign some object to this property and it will handle the Foo function for you.
Basically this is the only way to get close to what you're trying to do, though. Once you have created a method that could be overridden, then you can't prevent that some new object will override the method even further. But by using interfaces, you just force developers to use them in a certain way.
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12579323
... and if they passed in a nil?
0
 
LVL 2

Author Comment

by:__alex
ID: 12583297
Thanks again!
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12585217
If they pass nil, well... If that is possible then you have to check for it. Or create some default object if they pass nil. But since you can control this value from the Create() method, you can decide what you want to fill it with.
The use of interfaces might be what you are looking for but it is a bit complex.
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Integration Management Part 2
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Suggested Courses
Course of the Month12 days, 4 hours left to enroll

564 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question