我只是一个设计模式的初学者,刚刚学习了理论定义以及如何在代码中实现,但喜欢了解各种鼓励使用适配器模式的现实世界情况/案例/场景?
假设您有一个类来解析HTML文件以确保它们是有效的。它看起来像这样:
public class Parser
{
public Parser(string filePath)
{
...
}
public void Parse()
{
...
}
public bool IsValid()
{
...
}
}
假设你在一个应用程序中使用它。应用程序代码可能如下所示:
Parser p = new Parser("file.html");
p.Parse();
if(p.IsValid())
print "yay"
else
print "lame"
你写了Parser
类,它工作得很好,但你的朋友写了另一个工作得更好。假设它们的类是这样的:
public class BetterParser
{
public bool ParseHtml(FileStream fs)
{
...
}
}
现在你想使用你朋友的BetterParser
类而不是你的Parser
类,但它并不真正与你的代码工作,因为它有不同的方法名称和工作方式略有不同。您可以将上面的应用程序代码更改为如下内容:
FileStream fs = GetStream("test.html")
BetterParser bp = new BetterParser()
if(bp.ParseHtml(fs))
print "yay"
else
print "lame"
这很好,但是如果您有一个大型应用程序,您的Parser
类无处不在呢?您可能不想更改所有使用它的地方,因为这将需要大量额外的测试和潜在的bug。
你能做的就是使用适配器模式来改变你的类,使它在你朋友的实现中实际使用你的类。
class Parser
{
private BetterParser bp = new BetterParser();
private FileStream fs;
private boolean successful;
public Parser(string file)
{
fs = GetStream(file);
}
public void Parse()
{
successful = bp.ParseHtml(fs);
}
public boolean IsValid()
{
return successful;
}
}
您可以看到,现在您的类的实现在幕后使用了您朋友的类。因此,现在使用Parser类的所有代码都不必更改,并且您仍然可以获得使用更好的解析器的好处。
这基本上就是适配器模式的全部内容。它连接了两个不能直接相互连接的东西。在本例中,Parser类曾经是一个普通的HTML解析器,但它变成了一个适配器,将您的应用程序代码连接到您朋友的解析器。
关键在于将接口与实现分离。您的应用程序代码不应该依赖于解析器类的内部工作方式,而必须依赖于该类的接口。事实上,这个类有一个接受文件路径的构造函数,它有一个不接受参数的名为Parse
的方法,以及一个返回布尔值的名为IsValid
的方法。这些是类接口的所有方面,如果接口发生了变化,应用程序就不能在不进行更改的情况下使用该类。因此,您可以保持接口不变,并更改实现。
大于class
人们经常说适配器只是另一个类的"包装器"。当涉及到代码级别的适配器时,这可能在很多时候是正确的。但是,整个应用程序也可以用作适配器。假设您有一些服务器提供一些XML web服务API(即SOAP)。这意味着所有与之通信的客户机都需要理解XML。如果您想要连接一个不讲XML的客户机(也许它使用JSON),该怎么办?一种选择是在服务器和JSON框之间放一个框。这个新盒子将用作在XML和JSON之间进行转换的适配器。客户端使用JSON与适配器通信,适配器使用XML与服务器通信。
您可以考虑查看http://www.dofactory.com/net/adapter-design-pattern上的一两个示例。
AlexAtNet说"适配器"是"包装器"是正确的。当您有一个期望特定接口的消费者,但您有一个具有不同接口的源类时,您可以构建源的适配器来匹配消费者的期望。这里有一篇关于适配器与桥接器的不错的文章:http://fernandozamorajimenez.blogspot.com/2009/12/as-i-was-preparing-for-upcoming.html