生成器工厂返回不同的子接口 [英] Builder Factory returning different sub-interfaces

查看:86
本文介绍了生成器工厂返回不同的子接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道堆栈溢出有很多变化和相关主题,但是我没有找到任何令人信服的答案,所以我自己去解决。

I know there are many variations and related topics to this one here on stack overflow but I haven't found any compelling answers so I'll give it a go myself.

我正在尝试设计一个构建器工厂,该工厂返回一个通用构建器接口的不同子类。我想允许所有实现共享一个通用的抽象类,以供代码重用。

I'm trying to design a builder factory that returns different subclasses of a common builder interface. I want to allow all the implementations to share a common abstract class for code re-use.

请注意,我对<$ c的返回类型不感兴趣$ c> build()方法,仅显示建筑商的类型。

Note that I'm not interested in the return type of the build() method, only what types the builders are.

这是我到目前为止所拥有的:

This is what I have so far:

具有通用子接口的Builder接口:

Builder interface with generic for the sub-interfaces:

interface FruitBuilder<T extends FruitBuilder<T>> {
    T taste(String taste);
    T shape(String shape);
    T weight(String weight);

    Fruit build();
}

一些建筑商还有其他方法:

Some builders have additional methods:

interface GrapesBuilder extends FruitBuilder<GrapeBuilder> {
    GrapesBuilder clusterSize(int clusterSize);
}

下一步是指定返回特定建造者的工厂:

Next is to specify a factory that returns the specific builders:

interface FruitBuilderFactory {
    GrapesBuilder grapes();
    AppleBuilder apple();
    LemonBuilder lemon();
}

这些界面的用户应该可以像这样使用它:

A user of these interfaces should be able to use it like:

 Fruit grapes = fruitBuilderFactory
    .grapes()
    .weight(4)
    .color("Purple")
    .clusterSize(4)  // Note that the GrapesBuilder type must be accessible here!
    .build();

大多数逻辑将进入抽象类,包括高级构建逻辑:

Most of the logic would go into the abstract class, including advanced build logic:

abstract class BaseFruitBuilder<T extends FruitBuilder<T>> implements FruitBuilder<T> {

   String taste;

   T taste(String taste) {
       this.taste = taste;
       return (T)this;     // Ugly cast!!!!!
   }

   ...

    Fruit build() {
       Fruit fruit = createSpecificInstance();

       // Do a lot of stuff on the fruit instance.

       return fruit;
    }

    protected abstract Fruit createSpecificInstance();
}

鉴于基类,实现新构建器非常简单:

Given the base class, it's really simple to implement new builders:

class GrapseBuilderImpl extends BaseFruitBuilder<GrapesBuilder> {
   int clusterSize;
   GrapesBuilder clusterSize(int clusterSize) {
       this.clusterSize = clusterSize;
   }

   protected Fruit createSpecificInstance() {
       return new Grape(clusterSize);
   }
}

这一切都是编译好的(至少我的真实码)。我是否可以删除抽象类中对T的丑陋转换的问题。

This is all compiling and fine (at least my real code). The question if whether or not I can remove the ugly cast to T in the abstract class.

推荐答案

避免转换的一种选择是定义返回 T 的单个抽象方法:

One option to avoid casting is to define a single abstract method returning T:

abstract class BaseFruitBuilder<T extends FruitBuilder<T>> implements FruitBuilder<T> {

    String taste;

    T taste(String taste) {
       this.taste = taste;
       return returnThis();
    }

    protected abstract T returnThis();

     //...
}

class GrapseBuilderImpl extends BaseFruitBuilder<GrapesBuilder> {
    //...
    @Override
    protected T returnThis() {
        return this;
    }
}

缺点是您必须信任每个子类正确实施该方法。再一次,使用您的方法,没有什么能阻止任何人声明子类 GrapesBuilder扩展BaseFruitBuilder< AppleBuilder> ,因此您需要在某种程度上信任子类。

The downside is that you have to trust each subclass to implement the method correctly. Then again, with your approach, there's nothing stopping anyone from declaring a subclass GrapesBuilder extends BaseFruitBuilder<AppleBuilder>, so you'll need to trust subclasses to some extent.

编辑刚刚意识到此解决方案已由@ user158037的评论。我自己使用过,但从未意识到这是已知的成语。 :-)

EDIT Just realized this solution was referenced by @user158037's comment. I've used this myself, but never realized it was a known idiom. :-)

这篇关于生成器工厂返回不同的子接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆