I need to add some new functionality to an existing interface. There are already a lot o开发者_JAVA百科f classes in the project implementing it but a few of them wouldn't need the new set of features. My first approach was to just add the new functions to the existing interface and implementing it everywhere, adding do-nothing functions where applicable and the such. But now I wonder if there's a better way to do this.
As an example:
// Everything able to produce a waveform must implement this interface.
interface IWaveformResource
{
int Collect( Stream _target, int _sampleCount );
}
// A waveform stored in a file
class FileWaveform : IWaveformResource
{
public int Collect( Stream _target, int _sampleCount )
{
// ...
}
}
// A sine waveform.
class SineWaveform : IWaveformResource
{
public int Collect( Stream _target, int _sampleCount )
{
// ...
}
}
// Added feature, we want to be able to specify the read position
interface IWaveformResource
{
int Collect( Stream _target, int _sampleCount );
int ReadOffset { get; set; }
}
class FileWaveform : IWaveformResource
{
public int Collect( Stream _target, int _sampleCount )
{
// ...
}
// Moves the associated file pointer accordingly.
int ReadOffset { get; set; }
}
class SineWaveform : IWaveformResource
{
public int Collect( Stream _target, int _sampleCount )
{
// ...
}
// There's no point in setting or retrieving a sine wave's read position.
int ReadOffset { get; set; }
}
Another option would be to create a new interface which will only be implemented by positionable waveform streams, eg. FileWaveform :
interface IPositionableWaveform
{
int ReadOffset { get; set; }
}
// A waveform stored in a file
class FileWaveform : IWaveformResource, IPositionableWaveform
{
public int Collect( Stream _target, int _sampleCount )
{
// ...
}
}
and use it like this:
private List<IWaveformResource> mResources;
public int ReadOffset
{
set
{
foreach( IWaveformResource resource in mResources )
{
if( resource is IPositionableWaveform )
{
((IPositionableWaveform)resource).ReadOffset = value;
}
}
}
}
Note that in this approach I'm not forcing a IPositionableWaveform to be also a IWaveformResource.
I would like to know if there's a more elegant solution than this, thanks in advance.
No. Unfortunately, changing an existing interface is a breaking change.
This is, by the way, one of the stronger arguments for favoring abstract classes to interfaces - with an abstract base class, you can add members (with a default implementation) without breaking an API.
Introducing a second interface (inheriting from the first) is probably your best option. The main change I'd make, from what you're describing, would be to do:
public interface IWaveformResource : IAudioResource { ... }
This way, it's obvious that a Waveform Resource is also an audio resource.
If not all classes implementing the interface will need the new functionality, there is a good chance it should have never belonged to that interface anyway.
精彩评论