建造者模式-具有递归类型参数的泛型类型(Effective-Java)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了建造者模式-具有递归类型参数的泛型类型(Effective-Java)相关的知识,希望对你有一定的参考价值。


Effective-Java-Chapter 2:

建造者模式-具有递归类型参数的泛型类型(Effective-Java)_建造者模式

来看看书中的Pizza代码案例(我写了详细注释):

Pizza:

import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;

public abstract class Pizza
public enum Topping HAM, MUSHROOM, ONION, PEPPER, SAUSAGE

final Set<Topping> toppings;

//这种技术称为协变返回类型,其中一个子类方法声明为返回超类中声明的返回类型的子类型。
//它允许客户使用这些构建器,而不需要强制转换。(因为self()函数返回子类自身)
abstract static class Builder<T extends Builder<T>>
//此处限制了 T 只能是Builder的子类(目的:type safe)
EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);

public T addTopping(Topping topping)
toppings.add(Objects.requireNonNull(topping));
return self();


abstract Pizza build();

// Subclasses must override this method to return "this"
protected abstract T self();


Pizza(Builder<?> builder)
toppings = builder.toppings.clone(); // See Item 50

建造者模式-具有递归类型参数的泛型类型(Effective-Java)_后端开发_02

MyPizza:

import java.util.Objects;

public class NyPizza extends Pizza
public enum Size SMALL, MEDIUM, LARGE

private final Size size;
//Builder1是作者自己做的小修改,方便看区别
public static class Builder1 extends Pizza.Builder<Builder1>
//因为Builder1 extends Pizza.Builder 则 Pizza.Builder<Builder1>成立.
//Pizza.Builder<Builder1>写成Pizza.Builder<Builder2>编译成功
//因为Builder2是Pizza.Builder子类,不过这样的话,self()函数返回的就是Calzone对象了
//递归泛型作用就是限定泛型T只能是自己的子类,达到type safe的目的
private final Size size;

public Builder1(Size size)
this.size = Objects.requireNonNull(size);


@Override
public NyPizza build()
return new NyPizza(this);


@Override
protected Builder1 self()
return this;

//Self类型是在接口中用描述实现接口的具体类型的特殊类型标识,用来安全地从父类型向子类型转换对象
//一般来说,把父类型的对象转换为子类型的对象,都要用强制类型转换。
//利用递归的类型参数,可以避免强制类型转换


private NyPizza(Builder1 builder)
super(builder);
size = builder.size;

建造者模式-具有递归类型参数的泛型类型(Effective-Java)_java_03

Calzone:(与MyPizza类 类似的)

public class Calzone extends Pizza 
private final boolean sauceInside;

public static class Builder2 extends Pizza.Builder<Builder2>
private boolean sauceInside = false; // Default

public Builder2 sauceInside()
sauceInside = true;
return this;


@Override
public Calzone build()
return new Calzone(this);


@Override
protected Builder2 self()
return this;



private Calzone(Builder2 builder)
super(builder);
sauceInside = builder.sauceInside;

建造者模式-具有递归类型参数的泛型类型(Effective-Java)_后端开发_04

来看看这3个类之间的关系图(右键点击Pizza类,点那个显示图,就可以看)

注:Builder1和Builder2是我自己做的一点点修改,方便看区别

建造者模式-具有递归类型参数的泛型类型(Effective-Java)_建造者模式_05


书中接下来就提到了“协变返回类型”:

建造者模式-具有递归类型参数的泛型类型(Effective-Java)_建造者模式_06

T self() 方法 将所需子类对象返回,无需强制类型转换。其次,

Pizza类中的 Builder<T extends Builder<T>> 限制了 T 只能是Builder的子类

对递归类型参数的泛型类型还是不理解的话,可以看看知乎这篇文章:

​Java泛型递归模式的意义? - CNife的回答 - 知乎​

感谢支持!

以上是关于建造者模式-具有递归类型参数的泛型类型(Effective-Java)的主要内容,如果未能解决你的问题,请参考以下文章

具有逆变类型参数和 Unity 容器的泛型

Java中的泛型

GetMethod 的 Type[] 以获取具有两个参数和一个类型参数的泛型方法

Scala的泛型

Typescript - 确保泛型属性存在于具有描述性错误的泛型类型上

在具有泛型参数的泛型方法中使用 Spring RestTemplate