Request for advice about class design, inheritance/aggregation
I have started writing my own WebDAV server class in .NET, and the first class I'm starting with is a WebDAVListener
class, modelled after how the HttpListener
class works.
Since I don't want to reimplement the core http protocol handling, I will use HttpListener
for all its worth, and thus I have a question.
What would the suggested way be to handle this:
- Implement all the methods and properties found inside HttpListener, just changing the class types where it matters (ie. the GetContext + EndGetContext methods would return a different class for WebDAV contexts), and storing and using a
HttpListener
object internally - Construct WebDAVListener by passing it a HttpListener class to 开发者_JAVA技巧use?
- Create a wrapper for HttpListener with an interface, and constrct WebDAVListener by passing it an object implementing this interface?
If going the route of passing a HttpListener (disguised or otherwise) to the WebDAVListener, would you expose the underlying listener object through a property, or would you expect the program that used the class to keep a reference to the underlying HttpListener
?
Also, in this case, would you expose some of the methods of HttpListener
through the WebDAVListener
, like Start and Stop, or would you again expect the program that used it to keep the HttpListener
reference around for all those things?
My initial reaction tells me that I want a combination. For one thing, I would like my WebDAVListener
class to look like a complete implementation, hiding the fact that there is a HttpListener
object beneath it.
On the other hand, I would like to build unit-tests without actually spinning up a networked server, so some kind of mocking ability would be nice to have as well, which suggests I would like the interface-wrapper way.
One way I could solve this would be this:
public WebDAVListener()
: WebDAVListener(new HttpListenerWrapper())
{
}
public WebDAVListener(IHttpListenerWrapper listener)
{
}
And then I would implement all the methods of HttpListener (at least all those that makes sense) in my own class, by mostly just chaining the call to the underlying HttpListener object.
What do you think?
Final question: If I go the way of the interface, assuming the interface maps 1-to-1 onto the HttpListener class, and written just to add support for mocking, is such an interface called a wrapper or an adapter?
I'll answer your last question first: a class is an adapter if it implements some ITarget interface using a contained object matching some ISource -- an adapter from ISource to ITarget. In this case, there is no source interface, you're trying to add one in, so I'd call it a wrapper.
I'd be inclined to
Make a WebDavListener class which has all the methods it needs for its own behaviour, uses an HttpListener internally, and doesn't expose anything about that HttpListener.
If and when you need it, make IHttpListenerWrapper and HttpListenerWrapper as you suggest, and change the WebDavListener to take an IHttpListenerWrapper in its constructor. Assuming all the methods are the same, this should be a simple search-and-replace. You could even leave the original constructor in there and have it construct a wrapper and call the new constructor.
If and when you need it, make an IWebDavListener for it to implement, if you think you might want a dummy WebDAV listener for unit testing other things.
This sort of design issue is why I love refactoring tools like ReSharper: Extract Interface, Create Derived Implementation etc. make it much easier to make these sort of changes, so you can worry less about whether to do them now or later :-) (Assuming you are allowed to freely change the source later, of course, which depends how you're delivering things.)
精彩评论