请求有关类设计、继承/聚合的建议
我已经开始在 .NET 中编写自己的 WebDAV 服务器类,我开始使用的第一个类是 WebDAVListener
类,它以 HttpListener
类的工作方式为模型。
由于我不想重新实现核心 http 协议处理,因此我将使用 HttpListener 来充分发挥其价值,因此我有一个问题。
建议的处理方法是什么:
- 实现 HttpListener 中找到的所有方法和属性,只需更改重要的类类型(即 GetContext + EndGetContext 方法将为 WebDAV 上下文返回不同的类),然后存储和使用一个 HttpListener 对象在内部
- 通过传递一个 HttpListener 类来构造 WebDAVListener 来使用?
- 使用接口创建 HttpListener 的包装器,并通过向其传递实现此接口的对象来构造 WebDAVListener?
如果采用将 HttpListener(伪装或其他方式)传递给 WebDAVListener 的方式,您是否会通过属性公开底层侦听器对象,或者您是否期望使用该类的程序保留对底层 HttpListenerHttpListener< /代码>?
另外,在这种情况下,您是否会通过 WebDAVListener
公开 HttpListener
的一些方法(例如 Start 和 Stop),或者您是否会再次期望使用它的程序保留所有这些事情的 HttpListener
参考?
我的第一反应告诉我我想要一个组合。一方面,我希望我的 WebDAVListener
类看起来像一个完整的实现,隐藏了它下面有一个 HttpListener
对象的事实。
另一方面,我想在不实际启动网络服务器的情况下构建单元测试,因此某种模拟能力也很好,这表明我喜欢接口包装方式。
我可以解决这个问题的一种方法是:
public WebDAVListener()
: WebDAVListener(new HttpListenerWrapper())
{
}
public WebDAVListener(IHttpListenerWrapper listener)
{
}
然后我将在我自己的类中实现 HttpListener 的所有方法(至少是所有有意义的方法),主要是将调用链接到底层 HttpListener 对象。
你怎么认为?
最后一个问题:如果我采用接口的方式,假设接口一对一映射到 HttpListener 类,并且只是为了添加对模拟的支持而编写,那么这样的接口称为包装器还是适配器?
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 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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我首先回答你的最后一个问题:如果一个类使用与某个 ISource 匹配的包含对象(从 ISource 到 ITarget 的适配器)实现某个 ITarget 接口,那么它就是一个适配器。在这种情况下,没有源接口,您尝试添加一个源接口,所以我将其称为包装器。
我倾向于
创建一个 WebDavListener 类,它具有其自身行为所需的所有方法,在内部使用 HttpListener,并且不公开有关该 HttpListener 的任何内容。
如果您需要它,请按照您的建议创建 IHttpListenerWrapper 和 HttpListenerWrapper,并更改 WebDavListener 以在其构造函数中采用 IHttpListenerWrapper。假设所有方法都相同,这应该是一个简单的搜索和替换。您甚至可以将原始构造函数保留在那里,让它构造一个包装器并调用新的构造函数。
如果您需要它,如果您认为可能需要一个虚拟 WebDAV 侦听器来对其他内容进行单元测试,请为其实现创建一个 IWebDavListener。
这种设计问题就是为什么我喜欢像 ReSharper 这样的重构工具:提取接口、创建派生实现等,使进行此类更改变得更加容易,因此您可以不用担心是现在还是稍后进行:-) (当然,假设您以后可以自由更改源,这取决于您交付内容的方式。)
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.)