OOP design question

  • Thread starter Thread starter John Wood
  • Start date Start date
J

John Wood

I have a class (B) that derives from another class (A) - it provides a
specialization of that base class.

It turns out that the base class (A) needs to be replaceable. That is, I
need to be able to plug in new implementations (retaining the same
interface).

I cannot change the source code of A or B, it needs to be in a library that
is shipped out. But customers should be able to 'plug-in' new base classes.

Other than having a proxy class as A that delegates to a plug-in interface,
I can't see any other way of doing it. And I really don't like writing proxy
classes.

Anyone have any better ideas?

Thanks.
 
John,

In this case, instead of providing specialization through derivation,
you might want to supply an interface that is implemented, and then call
those as needed. Then, all interaction is done against the class that you
ship, where the specializations are the plug-ins. This way, if you add more
functionality, you just swap out that class.

Of course, this could be done without breaking existing code (new
implementations just use the new class, not the old one). Also, if you
require more from your specialized classes, define a new interface and
require that to be implemented.

Hope this helps.
 
Yes, but the problem is how that 'plugged-in' interface is exposed to the
consumer of the application. You see, the specialized class has to expose
every method of the interface directly, as well as the new methods it
provides itself.

Without creating a proxy class that implements the interface but delegates
each method to the implementation you 'plug-in', I can't see how you can
plug-in an implementation without changing the source code.

Understand what I mean?

Nicholas Paldino said:
John,

In this case, instead of providing specialization through derivation,
you might want to supply an interface that is implemented, and then call
those as needed. Then, all interaction is done against the class that you
ship, where the specializations are the plug-ins. This way, if you add more
functionality, you just swap out that class.

Of course, this could be done without breaking existing code (new
implementations just use the new class, not the old one). Also, if you
require more from your specialized classes, define a new interface and
require that to be implemented.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

John Wood said:
I have a class (B) that derives from another class (A) - it provides a
specialization of that base class.

It turns out that the base class (A) needs to be replaceable. That is, I
need to be able to plug in new implementations (retaining the same
interface).

I cannot change the source code of A or B, it needs to be in a library that
is shipped out. But customers should be able to 'plug-in' new base classes.

Other than having a proxy class as A that delegates to a plug-in interface,
I can't see any other way of doing it. And I really don't like writing proxy
classes.

Anyone have any better ideas?

Thanks.
 
Yes, but the problem is how that 'plugged-in' interface is exposed to the
consumer of the application. You see, the specialized class has to expose
every method of the interface directly, as well as the new methods it
provides itself.

You'll need some kind of object factory that returns the interface and has
some way of for plug-in assemblies to register themselves with it. My
current application framework has a 'PlugInManager' class that loads the
assemblies and passes each assembly to interested parties as they are
loaded.

For example, if I have an IFileExporter interface and a FileExporterManager
which maintains a list of available file exporters. As each plugin assembly
is loaded, it is passed to the FileExporterManager object. The
FileExporterManager than enumerates the public objects within the assembly
(using reflection) and extracts a list of all types implementing the
IFileExporter interface and places them in a list.

Later on I can internally ask the FileExporterManager 'Which exporters are
available' and present the list to the user who chooses one. Internally I
can they say to the FileExporterManager 'Ok, I want this one. Can you create
it for me?'. The manager then creates an instance of the object and returns
an IFileExporter reference for me to use.

Of course, you're not limited to interfaces. You could use abstract classes,
base classes, attributes or a combination.
Understand what I mean?

I hope the above is relevant and makes sense :)

n!
 
Yep and that sounds like a good way to manage the plugins.
But you have a factory that simply returns the plugin instance that
implements the interface. I have a class that inherits from a pluggable base
class that implements an interface -- there's no way to 'plug-in' a base
class without having a proxy to delegate to the plugin, if you know what I
mean?

But you've got me thinking. Maybe there is a way to modify the assembly
using the CodeDOM, to 'poke' the name of the new base class into the derived
class at runtime.

Or maybe it's just easier to write that proxy that delegates...

Thanks for your insight!
 
But you have a factory that simply returns the plugin instance that
implements the interface. I have a class that inherits from a pluggable base
class that implements an interface -- there's no way to 'plug-in' a base
class without having a proxy to delegate to the plugin, if you know what I
mean?

Oh, sorry. I think I see what you mean now. If I follow you correctly now,
you want the following:

public Foo : Bar
{
}

Where Foo is your class, but 'Bar' is pluggable? You can't do this with
inheritance (well, not in any sane way :). So yes, a proxy would be
required. Something like:

public interface IBar
{
void SomeMethod();
}

private abstract BarBase
{
private IBar instance;

public BarBase()
{
instance = Factory.CreateBarInstance();
}

public virtual void SomeMethod()
{
instance.SomeMethod();
}
}


private class Foo : BarBase
{
public override void SomeMethod()
{
// Do specialization...

base.SomeMethod();
}
}

Though, TBH I've never seen the above requirement before :)

n!
 
Where Foo is your class, but 'Bar' is pluggable? You can't do this with
inheritance (well, not in any sane way :). So yes, a proxy would be
required.

I wouldn't be so adverse to the proxy idea, just that the interface is huge
and during development will probably be changing frequently...
Though, TBH I've never seen the above requirement before :)

Back in the not-so-good-ol' days of COM, we could use aggregation to do
this. In fact I once wrote something that implemented aggregation in objects
that weren't developed to support it natively by patching the interface
v-table of an object at runtime!

Thank God I can't do this anymore ;)

Here's an article on aggregation http://www.dwam.net/docs/oleref/com_13.htm
if you're interested. Can't do this now because there's no QueryInterface to
override...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top