当前位置: 首页 > 面试题库 >

具有继承的生成器模式

唐星晖
2023-03-14
问题内容

我想将一个Web服务URL请求表示为一个对象,并发现在继承层次结构中可能有很多通用参数。一个请求可以有很多参数,一些是必选参数,而其他是可选参数,我相信Bloch的Builder模式是一个不错的选择,它可以使用流畅的接口模拟命名参数。

具体来说,我正在设计Google Maps网络服务API,该API具有常规的网络服务请求

http://maps.googleapis.com/maps/api/service/output?{parameters}

serviceoutput是必填参数,也是sensor必填参数。还有一个可选参数language

每个服务都有其一组必填和可选参数。Geocode服务具有两个可选参数boundsregion。它还具有互斥的强制性参数addresslocation,它们指定服务的类型(分别为直接或反向地理编码)。我用新的儿童班代表了这种互斥。

我想象这样的类层次结构:

  .-----.
  | Url |
  '-----'
     ^
     |
.---------.
| Request |
'---------'
     ^
     |----------------------------+--------------...
.---------.                 .------------.
| Geocode |                 | Directions |
'---------'                 '------------'
     ^                            ^
     |------------+               .
 .--------.  .---------.          .
 | Direct |  | Reverse |          .
 '--------'  '---------'

然后,我想执行以下操作:

String output = "xml";
boolean sensor = true;
String address = "Av. Paulista, São Paulo, Brasil";
Bounds bounds  = new Bounds(-20, -10, -25, -20); //Geographic rectangle
String region  = "br";
String lang    = "pt-BR";
Coord location = new Coord(-12,-22);

DirectGeocodeRequestUrl direct = 
    new DirectGeocodeRequestUrl.Builder(output, sensor, address)
                               .bounds(bounds)
                               .language(lang)
                               .build();

ReverseGeocodeRequestUrl reverse = 
    new ReverseGeocodeRequestUrl.Builder(output, sensor, location)
                                .language(lang)
                                .region(region)
                                .build();

如何创建一个使用来自其插入类和超类的参数和方法的生成器?


问题答案:

我们需要的是使用Builder内部类复制相同的层次结构。当我们需要方法链接时,我们需要一个getThis()返回层次结构叶对象的方法。为了将其类型向上传递给层次结构,父类具有一个通用类T,并且叶子与其T自身绑定。

它确保类型安全,并避免由于未初始化的强制性参数或拼写错误以及漂亮的流畅接口而引发任何异常。但是,它代表URL这样的简单结构,这是一个非常昂贵且复杂的设计。我希望它对某人有用-
我更喜欢最后的字符串连接。

RequestUrl:

public abstract class RequestUrl{
    public static abstract class Builder<T extends Builder<T>>{
        protected String output;
        protected boolean sensor;
        //Optional parameters can have default values
        protected String lang = "en";

        public Builder(String output, boolean sensor){
            this.output = output;
            this.sensor = sensor;
        }

        public T lang(String lang){
            this.lang = lang;
            return getThis();
        }

        public abstract T getThis();
    }

    final private String output;
    final private boolean sensor;
    final private String lang;

    protected <T extends Builder<T>> RequestUrl(Builder<T> builder){
        this.output = builder.output;
        this.sensor = builder.sensor;
        this.lang = builder.lang;
    }

    // other logic...
}

GeocodeRequestUrl:

public abstract class GeocodeRequestUrl extends RequestUrl {
    public static abstract class Builder<T extends Builder<T>>
        extends RequestUrl.Builder<Builder<T>>{

        protected Bounds bounds;
        protected String region = "us";

        public Builder(String output, boolean sensor){
            super( output, sensor );
        }

        public T bounds(Bounds bounds){
            this.bounds = bounds;
            return getThis();
        }

        public T region(String region){
            this.region = region;
            return getThis();
        }

        @Override
        public abstract T getThis();
    }

    final private Bounds bounds;
    final private String region;

    protected <T extends Builder<T>> GeocodeRequestUrl(Builder<T> builder){
        super (builder);
        this.bounds = builder.bounds;
        this.region = builder.region;
    }

    // other logic...
}

DirectGeocodeRequestUrl:

public class DirectGeocodeRequestUrl extends GeocodeRequestUrl {
    public static class Builder<Builder>
        extends GeocodeRequestUrl.Builder<Builder>{

        protected String address;

        public Builder(String output, boolean sensor, String address){
            super( output, sensor );
            this.address = address;
        }

        @Override
        public Builder getThis(){
            return this;
        }

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

    final private String address;

    protected DirectGeocodeRequestUrl(Builder builder){
        super (builder);
        this.address = builder.address;
    }

    // other logic...
}

ReverseGeocodeRequestUrl:

public class ReverseGeocodeRequestUrl extends GeocodeRequestUrl {
    public static class Builder<Builder>
        extends GeocodeRequestUrl.Builder<Builder>{

        protected Coord location;

        public Builder(String output, boolean sensor, Coord location){
            super( output, sensor );
            this.location = location;
        }

        @Override
        public Builder getThis(){
            return this;
        }

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

    final private Coord location;

    protected ReverseGeocodeRequestUrl(Builder builder){
        super (builder);
        this.location = builder.location;
    }

    // other logic...
}


 类似资料:
  • 问题内容: 我的对象层次结构随着继承树的加深而增加了复杂性。这些都不是抽象的,因此,它们的所有实例都或多或少地达到了目的。 由于参数数量很多,我想使用“构建器模式”来设置属性,而不是对多个构造函数进行编码。由于我需要适应所有排列,因此继承树中的叶类将具有伸缩构造函数。 当我在设计过程中遇到一些问题时,我已经浏览了这里的答案。首先,让我给您一个简单的,简短的示例来说明问题。 现在我们有一些代码可以继

  • 我基于这个答案实现了模式,我有以下asbtract配置: 我有以下具体配置: 这就是我使用它的方式 在X行我得到-找不到符号方法setHeight。我的错误是什么? 编辑 - 我将有一个扩展的诊断配置,必须扩展对话框配置等。我的意思是会有其他子类。

  • 你更喜欢/建议哪一个?

  • 我有一个BaseEntity,当我像这样制作mapper时,它有一个名为Customer的子级: Mapstruct不会自动映射BaseEntity字段。你能告诉我怎么做吗?

  • **代码:(类名已重命名)** 两个版本中的CheeseDTO YAML: 使用springdoc-openapi-ui 1.3.9,我的yaml是这样生成的: 昂首阔步3注释: OpenAPi生成器maven插件 有没有办法用springdoc-openapi-ui>1.4.0生成?我必须更改我的大摇大摆的注释或更改我的java生成器吗?

  • 问题内容: 我想从Javadoc实现的接口继承Javadoc 。我在Javadoc命令中包含了源代码,并正确继承了文档。 现在,我想知道是否可以使它生成的链接指向Web上的文档,而不是在我的网站上复制它,即“ Specified by:”链接将链接到外部页面。 这可能吗? 问题答案: 有可能,是的。为了能够包含继承的文档,必须在javadoc的sourcepath中找到接口A的源,但不应在传递给用