美文网首页
Effective Java - 用静态方法代替构造器

Effective Java - 用静态方法代替构造器

作者: DZQANN | 来源:发表于2022-04-26 19:34 被阅读0次

第1条 用静态方法代替构造器

静态工厂方法与设计模式中的工厂方法模式不同

静态工厂方法的优势

  1. 静态工厂方法有名称,可以更确切地描述正被返回的对象。这是比较重要的优势之一了,在编码的过程中,名字的好坏往往会决定代码的可读性。比如getInstance和newInstance对比起来,可以很明显的感觉到前者是单例,后者是多例的

  2. 不必在每次调用它们的时候都创建一个新对象。可以在类内部构造几个常用的单例常量,可以在一定程度上节约内存。比如Boolean.valueOf

  3. 可以返回原类型的子类型对象。这一点也是比较重要的功能了,不只是子类,如果构造方法里有参数的时候,也可以在静态方法中给这个参数赋上不同的值

    public class ValueParser<T> {
        private final Function<T, String> parser;
    
        private ValueParser(Function<T, String> parser) {
            this.parser = parser;
        }
    
        public static ValueParser<Boolean> bool() {
            return new ValueParser<>(String::valueOf);
        }
    
        public static ValueParser<String> string() {
            return new ValueParser<>(e -> e);
        }
    }
    
  4. 返回对象的类型可以根据输入的参数而变化。比如说OpenJdk的EnumSet,它的构造方法是默认类型的,noneOf的实现会根据具体的数量返回不同的类型。和上面第3点有些许重合

    EnumSet(Class<E>elementType, Enum<?>[] universe) {
            this.elementType = elementType;
            this.universe    = universe;
        }
    
    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
      Enum<?>[] universe = getUniverse(elementType);
      if (universe == null)
        throw new ClassCastException(elementType + " not an enum");
    
      if (universe.length <= 64)
        return new RegularEnumSet<>(elementType, universe);
      else
        return new JumboEnumSet<>(elementType, universe);
    }
    
  5. 返回对象的类型不需要在写这个方法的时候就存在。这个地方主要还是依赖反射。比如JDBC,在编写一系列框架的时候,并没有Driver的实现类,那就需要通过反射创建假设自己有了。比较经典的就是ServiceLoader。这个特性主要用在底层框架中,业务代码中很少会用到

静态工厂方法的缺点

  1. 类如果不含public或者protected的构造器, 就不能被子类化。静态工厂方法构造基本都是要把构造器私有化的。这条缺点其实也会变相的鼓励程序员多使用组合

  2. 不容易被程序员发现。书中提到的是因为这类方法不会像构造器一样在API文档中表明出来。我觉得这一点不太成立,反而书中的内容更像是规范大家命名。因为在实际使用中,我们自己写的类不会生成Java doc,而别人想要使用一定会打开这个类并且查看别人的使用方法。

    书中还列举了常见的几个命名:

    • from: 类型转换方法。

      Date d = Date.from(instant);
      
    • of: 聚集方法, 参数为多个, 返回的当前类型的实例包含了它们。

      Set<Ranl> cards = EnumSet.of(JACK, QUEEN, KING);
      
    • valueOf: 类型转换方法, 返回的实例与参数具有相同的值。

      BigInteger.valueOf(Integer.MAX_VALUE);
      
    • instancegetInstance: 返回的实例通过参数来描述(并不是和参数有一样的值)..对于单例来说, 该方法没有参数, 返回唯一的实例。

      StackWalker luke = StackWalker.getInstance(options);
      
    • createnewInstance: 像getInstance一样, 但newInstance能确保返回的每个实例都与其他实例不同。

      Object array = Array.newInstance(classObject, arrayLen);
      
    • getType: 和getInstance一样, Type表示返回的对象类型, 在工厂方法处于不同的类中的时候使用。

      FileStore fs = Files.getFileStore(path);
      
    • newType: 和newInstance一样, Type表示返回的对象类型, 在工厂方法处于不同的类中的时候使用。

      BufferedReader br = Files.newBufferedReader(path);
      
    • type: getTypenewType的简洁替代。

      List<Complaint> litany = Collections.list(legacyLitany);
      

    总结一下其实大概3中情况:

    1. 类型转换:of/from
    2. 单例多例构造方法:getInstance/newInstance
    3. 返回子类:newType

对于TMS来说,我们通常写的helper、wrapper、cache(cache基本是一定要用的)都可以使用这种构造方法。目前我看过的代码里,SaveTariff可以通过工厂进行改造,后面隔周分享的时候拿出来讨论下

相关文章

网友评论

      本文标题:Effective Java - 用静态方法代替构造器

      本文链接:https://www.haomeiwen.com/subject/hlhlyrtx.html