使用构建器模式的一些常见的、真实的例子是什么?它能给你买什么?为什么不直接使用工厂模式?


当前回答

. net StringBuilder类是构建器模式的一个很好的例子。它主要用于在一系列步骤中创建字符串。执行ToString()的最终结果始终是一个字符串,但该字符串的创建取决于使用StringBuilder类中的哪些函数。总而言之,基本思想是构建复杂的对象,并隐藏如何构建对象的实现细节。

其他回答

在前面的回答(双关语)的基础上,有一个很好的现实例子,就是Groovy对Builders的内置支持。

使用Groovy的MarkupBuilder创建XML 使用Groovy的StreamingMarkupBuilder创建XML Swing构建器 SwingXBuilder

请参阅Groovy文档中的构建器

对于多线程问题,我们需要为每个线程构建一个复杂的对象。对象表示正在处理的数据,并且可以根据用户输入进行更改。

我们能用工厂代替吗?是的

为什么我们没有呢?我想建造者更有意义。

工厂用于创建具有相同基本类型的不同类型的对象(实现相同的接口或基类)。

构建器一遍又一遍地构建同一类型的对象,但是构造是动态的,因此可以在运行时更改它。

构建器的另一个优点是,如果您有一个Factory,那么代码中仍然存在一些耦合,因为要让Factory工作,它必须知道它可能创建的所有对象。如果您添加了另一个可以创建的对象,则必须修改工厂类以包括他。这在抽象工厂中也会发生。

另一方面,对于构建器,您只需要为这个新类创建一个新的具体构建器。director类将保持不变,因为它在构造函数中接收构造器。

此外,构建器也有很多种。神风特攻队雇佣兵又给了一个。

/// <summary>
/// Builder
/// </summary>
public interface IWebRequestBuilder
{
    IWebRequestBuilder BuildHost(string host);

    IWebRequestBuilder BuildPort(int port);

    IWebRequestBuilder BuildPath(string path);

    IWebRequestBuilder BuildQuery(string query);

    IWebRequestBuilder BuildScheme(string scheme);

    IWebRequestBuilder BuildTimeout(int timeout);

    WebRequest Build();
}

/// <summary>
/// ConcreteBuilder #1
/// </summary>
public class HttpWebRequestBuilder : IWebRequestBuilder
{
    private string _host;

    private string _path = string.Empty;

    private string _query = string.Empty;

    private string _scheme = "http";

    private int _port = 80;

    private int _timeout = -1;

    public IWebRequestBuilder BuildHost(string host)
    {
        _host = host;
        return this;
    }

    public IWebRequestBuilder BuildPort(int port)
    {
        _port = port;
        return this;
    }

    public IWebRequestBuilder BuildPath(string path)
    {
        _path = path;
        return this;
    }

    public IWebRequestBuilder BuildQuery(string query)
    {
        _query = query;
        return this;
    }

    public IWebRequestBuilder BuildScheme(string scheme)
    {
        _scheme = scheme;
        return this;
    }

    public IWebRequestBuilder BuildTimeout(int timeout)
    {
        _timeout = timeout;
        return this;
    }

    protected virtual void BeforeBuild(HttpWebRequest httpWebRequest) {
    }

    public WebRequest Build()
    {
        var uri = _scheme + "://" + _host + ":" + _port + "/" + _path + "?" + _query;

        var httpWebRequest = WebRequest.CreateHttp(uri);

        httpWebRequest.Timeout = _timeout;

        BeforeBuild(httpWebRequest);

        return httpWebRequest;
    }
}

/// <summary>
/// ConcreteBuilder #2
/// </summary>
public class ProxyHttpWebRequestBuilder : HttpWebRequestBuilder
{
    private string _proxy = null;

    public ProxyHttpWebRequestBuilder(string proxy)
    {
        _proxy = proxy;
    }

    protected override void BeforeBuild(HttpWebRequest httpWebRequest)
    {
        httpWebRequest.Proxy = new WebProxy(_proxy);
    }
}

/// <summary>
/// Director
/// </summary>
public class SearchRequest
{

    private IWebRequestBuilder _requestBuilder;

    public SearchRequest(IWebRequestBuilder requestBuilder)
    {
        _requestBuilder = requestBuilder;
    }

    public WebRequest Construct(string searchQuery)
    {
        return _requestBuilder
        .BuildHost("ajax.googleapis.com")
        .BuildPort(80)
        .BuildPath("ajax/services/search/web")
        .BuildQuery("v=1.0&q=" + HttpUtility.UrlEncode(searchQuery))
        .BuildScheme("http")
        .BuildTimeout(-1)
        .Build();
    }

    public string GetResults(string searchQuery) {
        var request = Construct(searchQuery);
        var resp = request.GetResponse();

        using (StreamReader stream = new StreamReader(resp.GetResponseStream()))
        {
            return stream.ReadToEnd();
        }
    }
}

class Program
{
    /// <summary>
    /// Inside both requests the same SearchRequest.Construct(string) method is used.
    /// But finally different HttpWebRequest objects are built.
    /// </summary>
    static void Main(string[] args)
    {
        var request1 = new SearchRequest(new HttpWebRequestBuilder());
        var results1 = request1.GetResults("IBM");
        Console.WriteLine(results1);

        var request2 = new SearchRequest(new ProxyHttpWebRequestBuilder("localhost:80"));
        var results2 = request2.GetResults("IBM");
        Console.WriteLine(results2);
    }
}

当我想在Java中为XML使用标准XMLGregorianCalendar来对DateTime进行对象封送时,我听到了很多关于使用它是多么沉重和麻烦的评论。我试图控制xs:datetime结构中的XML字段来管理时区,毫秒等。

因此,我设计了一个实用程序,从GregorianCalendar或java.util.Date构建一个xml公历。

由于我工作的地方,我不允许在网上分享它,但这里有一个客户如何使用它的例子。它抽象了XMLGregorianCalendar的细节,并过滤了xs:datetime中较少使用的一些实现。

XMLGregorianCalendarBuilder builder = XMLGregorianCalendarBuilder.newInstance(jdkDate);
XMLGregorianCalendar xmlCalendar = builder.excludeMillis().excludeOffset().build();

假定此模式更像是一个过滤器,因为它将xmlCalendar中的字段设置为未定义,因此将它们排除在外,但它仍然“构建”它。我已经很容易地向构建器添加了其他选项,以创建xs:date和xs:time结构,并在需要时操作时区偏移量。

如果您曾经见过创建和使用XMLGregorianCalendar的代码,您就会看到这是如何使它更容易操作的。