你什么时候会使用建造者模式?

发布于 2025-01-13 03:07:16 字数 1435 浏览 0 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

为人所爱 2025-01-20 03:07:16

下面是一些争论在 Java 中使用该模式的原因和示例代码,但它是设计模式中四人帮所涵盖的构建器模式的实现。在 Java 中使用它的原因也适用于其他编程语言。

正如 Joshua Bloch 在Effective Java,第二版:

当设计其构造函数或静态工厂具有多个参数的类时,构建器模式是一个不错的选择。

我们都曾在某个时候遇到过一个带有构造函数列表的类,其中每次添加都会添加一个新的选项参数:

Pizza(int size) { ... }        
Pizza(int size, boolean cheese) { ... }    
Pizza(int size, boolean cheese, boolean pepperoni) { ... }    
Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) { ... }

这称为伸缩构造函数模式。此模式的问题在于,一旦构造函数为 4 个,或 5 个参数长,就会难以记住所需的参数顺序以及在给定情况下您可能需要的特定构造函数。

伸缩构造函数模式的一个替代JavaBean模式,您可以使用强制参数调用构造函数,然后调用任何可选的设置器:

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

这里的问题问题是,由于对象是通过多次调用创建的,因此在构造过程中可能会处于不一致的状态。这也需要大量额外的工作来确保线程安全。

更好的选择是使用构建器模式。

public class Pizza {
  private int size;
  private boolean cheese;
  private boolean pepperoni;
  private boolean bacon;

  public static class Builder {
    //required
    private final int size;

    //optional
    private boolean cheese = false;
    private boolean pepperoni = false;
    private boolean bacon = false;

    public Builder(int size) {
      this.size = size;
    }

    public Builder cheese(boolean value) {
      cheese = value;
      return this;
    }

    public Builder pepperoni(boolean value) {
      pepperoni = value;
      return this;
    }

    public Builder bacon(boolean value) {
      bacon = value;
      return this;
    }

    public Pizza build() {
      return new Pizza(this);
    }
  }

  private Pizza(Builder builder) {
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.bacon;
  }
}

请注意,Pizza 是不可变的,并且参数值都位于单个位置。因为 Builder 的 setter 方法返回 Builder 对象,所以它们能够链接

Pizza pizza = new Pizza.Builder(12)
                       .cheese(true)
                       .pepperoni(true)
                       .bacon(true)
                       .build();

这使得代码易于编写,并且非常易于阅读和理解。在本示例中,可以修改构建方法以在参数复制后检查参数将构建器添加到 Pizza 对象,如果提供了无效的参数值,则抛出 IllegalStateException。这种模式很灵活,将来可以轻松向其添加更多参数。仅当构造函数的参数超过 4 或 5 个时,它才真正有用。也就是说,如果您怀疑将来可能会添加更多参数,那么首先这可能是值得的。

我从《Effective Java,第二版》一书中大量借用了有关此主题的内容 /em> 约书亚·布洛赫。要了解有关此模式和其他有效 Java 实践的更多信息,我强烈推荐它。

Below are some reasons arguing for the use of the pattern and example code in Java, but it is an implementation of the Builder Pattern covered by the Gang of Four in Design Patterns. The reasons you would use it in Java are also applicable to other programming languages as well.

As Joshua Bloch states in Effective Java, 2nd Edition:

The builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters.

We've all at some point encountered a class with a list of constructors where each addition adds a new option parameter:

Pizza(int size) { ... }        
Pizza(int size, boolean cheese) { ... }    
Pizza(int size, boolean cheese, boolean pepperoni) { ... }    
Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) { ... }

This is called the Telescoping Constructor Pattern. The problem with this pattern is that once constructors are 4 or 5 parameters long it becomes difficult to remember the required order of the parameters as well as what particular constructor you might want in a given situation.

One alternative you have to the Telescoping Constructor Pattern is the JavaBean Pattern where you call a constructor with the mandatory parameters and then call any optional setters after:

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

The problem here is that because the object is created over several calls it may be in an inconsistent state partway through its construction. This also requires a lot of extra effort to ensure thread safety.

The better alternative is to use the Builder Pattern.

public class Pizza {
  private int size;
  private boolean cheese;
  private boolean pepperoni;
  private boolean bacon;

  public static class Builder {
    //required
    private final int size;

    //optional
    private boolean cheese = false;
    private boolean pepperoni = false;
    private boolean bacon = false;

    public Builder(int size) {
      this.size = size;
    }

    public Builder cheese(boolean value) {
      cheese = value;
      return this;
    }

    public Builder pepperoni(boolean value) {
      pepperoni = value;
      return this;
    }

    public Builder bacon(boolean value) {
      bacon = value;
      return this;
    }

    public Pizza build() {
      return new Pizza(this);
    }
  }

  private Pizza(Builder builder) {
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.bacon;
  }
}

Note that Pizza is immutable and that parameter values are all in a single location. Because the Builder's setter methods return the Builder object they are able to be chained.

Pizza pizza = new Pizza.Builder(12)
                       .cheese(true)
                       .pepperoni(true)
                       .bacon(true)
                       .build();

This results in code that is easy to write and very easy to read and understand. In this example, the build method could be modified to check parameters after they have been copied from the builder to the Pizza object and throw an IllegalStateException if an invalid parameter value has been supplied. This pattern is flexible and it is easy to add more parameters to it in the future. It is really only useful if you are going to have more than 4 or 5 parameters for a constructor. That said, it might be worthwhile in the first place if you suspect you may be adding more parameters in the future.

I have borrowed heavily on this topic from the book Effective Java, 2nd Edition by Joshua Bloch. To learn more about this pattern and other effective Java practices I highly recommend it.

假情假意假温柔 2025-01-20 03:07:16

考虑一家餐馆。 “今天的饭菜”的创建是一种工厂模式,因为你告诉厨房“给我今天的饭菜”,厨房(工厂)根据隐藏的标准决定生成什么对象。

如果您订购定制披萨,则会出现生成器。在这种情况下,服务员告诉厨师(建造者)“我需要一个披萨;添加奶酪、洋葱和培根!”因此,构建器公开了生成的对象应具有的属性,但隐藏了如何设置它们。

Consider a restaurant. The creation of "today's meal" is a factory pattern, because you tell the kitchen "get me today's meal" and the kitchen (factory) decides what object to generate, based on hidden criteria.

The builder appears if you order a custom pizza. In this case, the waiter tells the chef (builder) "I need a pizza; add cheese, onions and bacon to it!" Thus, the builder exposes the attributes the generated object should have, but hides how to set them.

北斗星光 2025-01-20 03:07:16

恕我直言,构建器和工厂之间的主要区别在于,当您需要做很多事情来构建对象时,构建器非常有用。例如想象一个 DOM。您必须创建大量节点和属性才能获得最终对象。当工厂可以在一个方法调用中轻松创建整个对象时,就可以使用工厂。

使用构建器的一个示例是构建 XML 文档,我在构建 HTML 片段时使用了此模型,例如我可能有一个构建器用于构建特定类型的表,它可能具有以下方法(参数是未显示)

BuildOrderHeaderRow()
BuildLineItemSubHeaderRow()
BuildOrderRow()
BuildLineItemSubRow()

然后该构建器将为我输出 HTML。这比遍历大型过程方法更容易阅读。

查看维基百科上的构建器模式

The key difference between a builder and factory IMHO, is that a builder is useful when you need to do lots of things to build an object. For example imagine a DOM. You have to create plenty of nodes and attributes to get your final object. A factory is used when the factory can easily create the entire object within one method call.

One example of using a builder is a building an XML document, I've used this model when building HTML fragments for example I might have a Builder for building a specific type of table and it might have the following methods (parameters are not shown):

BuildOrderHeaderRow()
BuildLineItemSubHeaderRow()
BuildOrderRow()
BuildLineItemSubRow()

This builder would then spit out the HTML for me. This is much easier to read than walking through a large procedural method.

Check out Builder Pattern on Wikipedia.

遮了一弯 2025-01-20 03:07:16

.NET StringBuilder 类是构建器模式的一个很好的示例。它主要用于通过一系列步骤创建字符串。执行 ToString() 得到的最终结果始终是一个字符串,但该字符串的创建根据使用 StringBuilder 类中的函数而有所不同。总而言之,基本思想是构建复杂的对象并隐藏其构建方式的实现细节。

.NET StringBuilder class is a great example of builder pattern. It is mostly used to create a string in a series of steps. The final result you get on doing ToString() is always a string but the creation of that string varies according to what functions in the StringBuilder class were used. To sum up, the basic idea is to build complex objects and hide the implementation details of how it is being built.

听不够的曲调 2025-01-20 03:07:16

我一直不喜欢构建器模式,因为它笨拙、唐突,而且经常被经验不足的程序员滥用。这种模式只有在您需要从某些需要初始化后步骤的数据组装对象时才有意义(即一旦收集了所有数据 - 对其进行处理)。相反,99% 的情况下,构建器只是简单地用于初始化类成员。

在这种情况下,最好在类中简单地声明 withXyz(...) 类型 setter,并让它们返回对其自身的引用。

考虑一下:

public class Complex {

    private String first;
    private String second;
    private String third;

    public String getFirst(){
       return first; 
    }

    public void setFirst(String first){
       this.first=first; 
    }

    ... 

    public Complex withFirst(String first){
       this.first=first;
       return this; 
    }

    public Complex withSecond(String second){
       this.second=second;
       return this; 
    }

    public Complex withThird(String third){
       this.third=third;
       return this; 
    }

}


Complex complex = new Complex()
     .withFirst("first value")
     .withSecond("second value")
     .withThird("third value");

现在我们有一个整洁的单个类,它管理自己的初始化,并且执行与构建器几乎相同的工作,只是它更加优雅。

I always disliked the Builder pattern as something unwieldy, obtrusive and very often abused by less experienced programmers. Its a pattern which only makes sense if you need to assemble the object from some data which requires a post-initialisation step (i.e. once all the data is collected - do something with it). Instead, in 99% of the time builders are simply used to initialise the class members.

In such cases it is far better to simply declare withXyz(...) type setters inside the class and make them return a reference to itself.

Consider this:

public class Complex {

    private String first;
    private String second;
    private String third;

    public String getFirst(){
       return first; 
    }

    public void setFirst(String first){
       this.first=first; 
    }

    ... 

    public Complex withFirst(String first){
       this.first=first;
       return this; 
    }

    public Complex withSecond(String second){
       this.second=second;
       return this; 
    }

    public Complex withThird(String third){
       this.third=third;
       return this; 
    }

}


Complex complex = new Complex()
     .withFirst("first value")
     .withSecond("second value")
     .withThird("third value");

Now we have a neat single class that manages its own initialization and does pretty much the same job as the builder, except that its far more elegant.

天赋异禀 2025-01-20 03:07:16

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

我们可以用工厂代替吗?是的,

我们为什么不呢?我想 Builder 更有意义。

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

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

For a multi-threaded problem, we needed a complex object to be built up for each thread. The object represented the data being processed, and could change depending on the user input.

Could we use a factory instead? Yes

Why didn't we? Builder makes more sense I guess.

Factories are used for creating different types of objects that are the same basic type (implement the same interface or base class).

Builders build the same type of object over and over, but the construction is dynamic so it can be changed at runtime.

故事和酒 2025-01-20 03:07:16

当您有很多选择需要处理时,您可以使用它。想想 jmock 之类的东西:

m.expects(once())
    .method("testMethod")
    .with(eq(1), eq(2))
    .returns("someResponse");

感觉更自然,而且……可能。

还有 xml 构建、字符串构建和许多其他内容。想象一下,如果 java.util.Map 已作为构建器放置。你可以做这样的事情:

Map<String, Integer> m = new HashMap<String, Integer>()
    .put("a", 1)
    .put("b", 2)
    .put("c", 3);

You use it when you have lots of options to deal with. Think about things like jmock:

m.expects(once())
    .method("testMethod")
    .with(eq(1), eq(2))
    .returns("someResponse");

It feels a lot more natural and is...possible.

There's also xml building, string building and many other things. Imagine if java.util.Map had put as a builder. You could do stuff like this:

Map<String, Integer> m = new HashMap<String, Integer>()
    .put("a", 1)
    .put("b", 2)
    .put("c", 3);
恰似旧人归 2025-01-20 03:07:16

在研究 Microsoft MVC 框架时,我想到了构建器模式。我在 ControllerBuilder 类中遇到了该模式。该类将返回控制器工厂类,然后使用该工厂类来构建具体的控制器。

我看到使用构建器模式的优点是,您可以创建自己的工厂并将其插入框架中。

@Tetha,可能有一家由意大利人经营的餐厅(框架),供应披萨。为了准备披萨,意大利人(对象生成器)使用 Owen(工厂)和披萨底座(基类)。

现在印度人从意大利人手中接管了这家餐厅。印度餐厅(框架)提供薄饼而不是披萨。为了准备 dosa 印度人(对象构建者)使用带有 Maida(基类)的煎锅(工厂)

如果你看看场景,食物是不同的,食物准备的方式是不同的,但在同一家餐厅(在同一框架下) )。餐厅的建造方式应该能够支持中餐、墨西哥菜或任何美食。框架内的对象生成器有助于插入您想要的菜肴。例如

class RestaurantObjectBuilder
{
   IFactory _factory = new DefaultFoodFactory();

   //This can be used when you want to plugin the 
   public void SetFoodFactory(IFactory customFactory)
   {
        _factory = customFactory;
   }

   public IFactory GetFoodFactory()
   {
      return _factory;
   }
}

While going through Microsoft MVC framework, I got a thought about builder pattern. I came across the pattern in the ControllerBuilder class. This class is to return the controller factory class, which is then used to build concrete controller.

Advantage I see in using builder pattern is that, you can create a factory of your own and plug it into the framework.

@Tetha, there can be a restaurant (Framework) run by Italian guy, that serves Pizza. In order to prepare pizza Italian guy (Object Builder) uses Owen (Factory) with a pizza base (base class).

Now Indian guy takes over the restaurant from Italian guy. Indian restaurant (Framework) servers dosa instead of pizza. In order to prepare dosa Indian guy (object builder) uses Frying Pan (Factory) with a Maida (base class)

If you look at scenario, food is different,way food is prepared is different, but in the same restaurant (under same framework). Restaurant should be build in such a way that it can support Chinese, Mexican or any cuisine. Object builder inside framework facilitates to plugin kind of cuisine you want. for example

class RestaurantObjectBuilder
{
   IFactory _factory = new DefaultFoodFactory();

   //This can be used when you want to plugin the 
   public void SetFoodFactory(IFactory customFactory)
   {
        _factory = customFactory;
   }

   public IFactory GetFoodFactory()
   {
      return _factory;
   }
}
百变从容 2025-01-20 03:07:16

基于之前的答案(双关语),一个很好的现实示例是 Groovy 的内置支持建设者

请参阅构建器Groovy 文档

Building on the previous answers (pun intended), an excellent real-world example is Groovy's built in support for Builders.

See Builders in the Groovy Documentation

只有影子陪我不离不弃 2025-01-20 03:07:16

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

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

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

Another advantage of the builder is that if you have a Factory, there is still some coupling in you code, because for the Factory to work, it has to know all the objects it can possibly create. If you add another object that could be created, you will have to modify the factory class to include him. This happens in the Abstract Factory as well.

With the builder, on the other hand, you just have to create a new concrete builder for this new class. The director class will stay the same, because it receives the builder in the constructor.

Also, there are many flavors of builder. Kamikaze Mercenary`s gives another one.

软甜啾 2025-01-20 03:07:16
/// <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);
    }
}
/// <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);
    }
}
|煩躁 2025-01-20 03:07:16

我在本地消息库中使用了构建器。库核心从线路接收数据,使用 Builder 实例收集数据,然后,一旦 Builder 确定它已获得创建 Message 实例所需的一切,Builder.GetMessage() 就会使用从 Builder 收集的数据构建消息实例。金属丝。

I used builder in home-grown messaging library. The library core was receiving data from the wire, collecting it with Builder instance, then, once Builder decided it've got everything it needed to create a Message instance, Builder.GetMessage() was constructing a message instance using the data collected from the wire.

°如果伤别离去 2025-01-20 03:07:16

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

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

由于我的工作地点的原因,我不允许在没有法律的情况下在线共享它,但这里有一个客户如何使用它的示例。它抽象了细节并过滤了一些较少用于 xs:datetime 的 XMLGregorianCalendar 实现。

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

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

如果您曾经见过创建和使用 XMLGregorianCalendar 的代码,您就会发现这如何使其更易于操作。

When I wanted to use the standard XMLGregorianCalendar for my XML to object marshalling of DateTime in Java, I heard a lot of comments on how heavy weight and cumbersome it was to use it. I was trying to comtrol the XML fields in the xs:datetime structs to manage timezone, milliseconds, etc.

So I designed a utility to build an XMLGregorian calendar from a GregorianCalendar or java.util.Date.

Because of where I work I'm not allowed to share it online without legal, but here's an example of how a client uses it. It abstracts the details and filters some of the implementation of XMLGregorianCalendar that are less used for xs:datetime.

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

Granted this pattern is more of a filter as it sets fields in the xmlCalendar as undefined so they are excluded, it still "builds" it. I've easily added other options to the builder to create an xs:date, and xs:time struct and also to manipulate timezone offsets when needed.

If you've ever seen code that creates and uses XMLGregorianCalendar, you would see how this made it much easier to manipulate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文