Java泛型+ Builder模式

Jas*_*n S 23 java generics builder

我如何在start()下面打电话?

package com.example.test;

class Bar {}

public class Foo<K>
{
    final private int count;
    final private K key;

    Foo(Builder<K> b)
    {
        this.count = b.count;
        this.key = b.key;
    }

    public static class Builder<K2>
    {
        int count;
        K2 key;

        private Builder() {}
        static public <K3> Builder<K3> start() { return new Builder<K3>(); }
        public Builder<K2> setCount(int count) { this.count = count; return this; }
        public Builder<K2> setKey(K2 key) { this.key = key; return this; }
        public Foo<K2> build() { return new Foo(this); }
    }

    public static void main(String[] args)
    {
        Bar bar = new Bar();
        Foo<Bar> foo1 = Foo.Builder.start().setCount(1).setKey(bar).build();
        // Type mismatch: cannot convert from Foo<Object> to Foo<Bar>

        Foo<Bar> foo2 = Foo.Builder<Bar>.start().setCount(1).setKey(bar).build();
        // Multiple markers at this line
        // - Bar cannot be resolved
        // - Foo.Builder cannot be resolved
        // - Syntax error on token ".", delete this token
        // - The method start() is undefined for the type Foo<K>
        // - Duplicate local variable fooType mismatch: cannot convert from Foo<Object> to Foo<Bar>

        Foo<Bar> foo3 = Foo<Bar>.Builder.start().setCount(1).setKey(bar).build();
        // Multiple markers at this line
        // - Foo cannot be resolved
        // - Syntax error on token ".", delete this token
        // - Bar cannot be resolved     
    }
}
Run Code Online (Sandbox Code Playgroud)

And*_*anu 30

你很亲密:

Foo.Builder.<Bar> start().setCount(1).setKey(bar).build();
Run Code Online (Sandbox Code Playgroud)

干杯! :)

PS如果编译器无法自己推断方法的类型参数,可以通过调用强制它obj.<Type> method(...).

您可能想要使用的PPS:

public Foo<K2> build() {
    return new Foo<K2>(this);
}
Run Code Online (Sandbox Code Playgroud)

避免使用原始类型.

  • 每当您在方法中写下显式类型参数时,上帝就会杀死一只小猫;) (2认同)
  • @Jason:提供start()方法的密钥并将其传递给私有构造函数,以便得到类似的东西:Bar bar = new Bar(); Foo.Builder.start(巴); //类型将从bar推断出来 (2认同)
  • @Jason我认为小猫引用最初来自Josh Bloch.我自己使用它,至少偶尔使用一次.如果你自己只使用这个构建器,那就去吧.但是,如果有其他开发人员,我的回答可能会更容易.显式类型参数不是很漂亮,甚至更重要 - 不是每个开发人员都知道它们存在.只要看看你.你必须来这里才能让他们工作.同样,其他开发人员也很难使用使用它们的库.最后,它归结为可用性和品味问题. (2认同)

sfu*_*ger 21

Andrei的方法没问题,但是大多数程序员可能会对相当未知的语法感到困惑.使用这种方式可能更容易:

static public <K3> Builder<K3> start(Class<K3> cls) { return new Builder<K3>(); }

Foo<Bar> foo1 = Foo.Builder.start(Bar.class).setCount(1).setKey(bar).build();
Run Code Online (Sandbox Code Playgroud)

该类仅传递给泛型类型的帮助.它不漂亮,但至少语法是常识.

另一种选择是立即开始使用泛型类型的对象:

Foo<Bar> foo1 = Foo.Builder.startWithKey(bar).setCount(1).build();
Run Code Online (Sandbox Code Playgroud)


Yub*_*raj 9

如果您是lombok项目的粉丝并使用其注释@Builder来实现构建器模式,那么您可以像编写一样删除所有不必要的代码,并用更少的代码来完成。

例子:

@Builder
public class ErrorResponse<T> {
    private String message;
    private List<String> reasons;
    private List<String> details;
    private T data;
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样初始化它:

ErrorResponse<MyData> myDataError = ErrorResponse.<MyData>builder()
.message("My message")
.build();
Run Code Online (Sandbox Code Playgroud)