java 静态工厂代替多参构造器的适用情况与优劣

背景

假如现在你要想一个汉堡,有一个汉堡类:Hamburg。那么一般情况下你会:

Hamburg hamburg = new Hamburg();

情景一:不同参数数目的构造器

制作汉堡可以选择自定义,加肉,加菜,或者不添加,直接默认配方即可,那么会有以下几个构造器:

Hamburg();
Hamburg(Meat meat);
Hamburg(Meat meat,Vegetable vegetable);

当你要制作汉堡的时候,看到这么多的构造器,但是却不知道他们是什么意思,返回的汉堡到底有什么区别?查文档又有点麻烦,有没有更好的解决方法呢?

情景二:不同种类的汉堡

如果有多种汉堡:新奥尔良汉堡,麦辣香汉堡。常规的做法就是:继承汉堡类,实现子类,如:

class xinaoerliangHamburg extends Hamburg{}
class mailaHamburg extends Hamburg{}

但是会有问题:用户在使用的时候,还得记住你那么多类名,那是不是很麻烦?如果后续有更多的口味,那是不是要记住更多地类去才能得到对应的实例呢?有没有更好的解决方法?

情景三:自定义汉堡的做法

如果汉堡的手法让你非常不满意,你想要用达芬奇技法来制作汉堡,那么可以怎么做呢?常规的做法是:

class Hamburg{
 ...
 //默认制作手法
 private Maker mMaker = new DefaultMaker();
 public Hamburg(Maker maker){
  ...
  //使用传进来的手法对象制作汉堡
  mMaker = maker;
  ...
 }
}

需要重新写一个构造器,传入参数来覆盖原来的制作手法。这样既有情景一的问题,还有另外的问题是:如果需要自定义的东西多的时候,那么Hamburg里需要维护的代码就更加的复杂了。

什么是静态工厂方法

以上情景问题可以通过静态工厂方法来改善。

注意,这里的静态工厂方法并不是设计模式中的工厂模式。这里只是使用静态工厂方法来代替构造器实例化对象。

顾名思义,静态工厂方法,就是使用静态方法来构建类的实例,解决使用构造器实例化的各种问题。先看个例子,还是以上面的汉堡为例子,如果需要多种口味的汉堡,那么可以:

class Hamburg{

 //获取奥尔良口味的汉堡
 public static Hamburg ofAoErLiang(){
  return new AoErLiangHamburg();
 }
 //获取麦辣香味的汉堡
 public static Hamburg ofMaiLaXiang(){
  return new MaiLaXiangHamburg();
 }
}

//两种口味的汉堡,通过继承汉堡实现
class AoErLiangHamburg extends Hamburg{}
class MaiLaXiangHamburg extends Hamburg{}

通过这种方法可以解决的是:用户需要什么类型的汉堡,可以直接通过Hamburg的静态方法来获取,而无需知道他的子类名字是什么。而如果有更多种口味的汉堡,只需要扩展静态方法即可;或者给静态方法增加参数,通过switch来返回对应的口味汉堡。

静态工厂优缺点

这里的话会结合上面举的例子,如果忘记了,看到可以返回去看一下。

优点

  • 解决构造器重载却不知道各种构造器含义的问题。通过构造方法可以在方法名写明,那么用户只需要通过方法名就知道这个方法是返回什么对象。(例如情景一)例如:
//不同的静态工厂方法返回不同的实例,通过方法名就知道他们的区别
//ps:这是android的动画类
ObjectAnimator animator = ObjectAnimator.ofFloat();
ObjectAnimator animator = ObjectAnimator.ofInt();
  • 可以通过根据用户的参数或者调用不同的静态工厂方法来返回具体的子类对象。当后期要更换方法接口返回的子类时,对于用户来说也是透明的,用户只是拿到一个父类引用的对象。可以参考上面我在介绍静态工厂方法举的例子。

Java 8以上,可以在接口中定义静态工厂方法,这样无需知道该接口有多少个实现类,只需要根据静态方法来获取接口对象即可。

  • 重复利用对象,防止创建无用实例。这看起来很像单例,但是比单例要灵活得多。可以根据具体的情况,来判断是否要缓存实例。
  • 可以动态注册代码。我们可以通过一组用户注册api,让用户先把需要的自定义代码注入,再调用静态方法来获取自己需要的对象类型。这样的好处就是不会有一堆很复杂的构造器,内部逻辑也可以分离。对应情景三解决的问题

缺点

  1. 如果该类不包含public或者protect构造器,那么将无法被子类实例化。因为我们想要用户通过静态方法来获取对象,而不喜欢用户通过构造方法来实例化对象。而如果把构造器设置为private,则无法被子类继承。
  2. 无法在javadoc中直接查看文档介绍,构造器是会直接生成doc的。但是直接通过方法名和参数名,已经可以看懂很多了。

静态方法命名规范

方法名 含义
fromXxx  类型转换
ofXxx 多个参数聚合
valueOf 和from of类似
getInstance  获取一个实例,实例类型通过方法参数描述
getNewInstance/create 获取一个新的实例
getType 主要用于工厂方法中获取不同类的对象(属于设计模式中的工厂方法)
newType 新建一个对应类的对象(属于设计模式中的工厂方法)
type  上面两者的简化版

小结

在有多种子类或者重载构造器的时候,可以优先考虑一下静态工厂方法,可以让我们的代码更加地优雅,也方便我们进行维护。
另外这和设计模式中的工厂模式有区别,并不是一样的,要进行区分。

参考资料

《effective java》

以上就是java 静态工厂代替多参构造器的详细内容,更多关于java 静态工厂的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java 构造器原理及用法解析

    导读 构造器是编程的强大组件.使用它们来释放 Java 的全部潜力. 在开源.跨平台编程领域,Java 无疑(?)是无可争议的重量级语言.尽管有许多伟大的跨平台框架,但很少有像 Java 那样统一和直接的. 当然,Java 也是一种非常复杂的语言,具有自己的微妙之处和惯例.Java 中与构造器 constructor有关的最常见问题之一是:它们是什么,它们的作用是什么? 简而言之:构造器是在 Java 中创建新对象object时执行的操作.当 Java 应用程序创建一个你编写的类的实例时,它将检

  • Java设计模式之静态工厂模式详解

    本文实例讲述了Java设计模式之静态工厂模式.分享给大家供大家参考,具体如下: 静态工厂模式(static factory)也叫简单工厂模式. 涉及到3个角色:工厂类角色,抽象产品类角色和具体产品类角色. 抽象产品类可以使用接口或者父类来描述产品对象的行为特征. 具体产品类就是某一具体的对象. 静态工厂类有一个静态的方法,含有判断逻辑,决定要创建哪一种具体的产品对象. 其设计模式如下: 抽象产品类  IProduct package org.test.design.sf; public inte

  • java中构造器内部调用构造器实例详解

    可能为一个类写了多个构造器,有时可能想在一个构造器里面调用另外一个构造器,为了减少代码的重复,可用this关键字做到这一点. public class Flower { private String string; private int age; public Flower() { // 先调用public Flower(String string, int age) this("leon", 120); // 先调用public Flower(String string, int

  • Java构造器(构造方法)与方法区别说明

    构造器,又称为构造方法.构造器用于构造该类的实例,也就是对象. 格式如下:[修饰符] 类名 (形参列表){//n条语句} 构造方法是一种特殊的方法,与一般的方法区别: 1.构造方法的名字必须与定义他的类名完全相同,没有返回类型,甚至连void也没有. 2.构造方法的调用是在创建一个对象时使用new操作进行的.构造方法的作用是初始化对象. 3.不能被static.final.synchronized.abstract和native修饰.构造方法不能被子类继承. 构造方法可以被重载.没有参数的构造方

  • Java 7菱形语法与泛型构造器实例分析

    本文实例讲述了Java 7菱形语法与泛型构造器.分享给大家供大家参考,具体如下: 一 实战--泛型构造器 1 代码 class Foo { public <T> Foo(T t) { System.out.println(t); } } public class GenericConstructor { public static void main(String[] args) { // 泛型构造器中的T参数为String. new Foo("疯狂Java讲义"); //

  • Java Lambda表达式的方法引用和构造器引用实例分析

    本文实例讲述了Java Lambda表达式的方法引用和构造器引用.分享给大家供大家参考,具体如下: 一 点睛 如果Lambda表达式的代码块只有一条代码,还可以在代码块中使用方法引用和构造器引用,以使得Lambda表达式更加简洁. 种类 示例 说明 对应的Lambda表达式 引用类方法 类名::类方法 函数式接口中被实现方法的全部参数传给该类方法作为参数. (a,b,...) -> 类名.类方法(a,b, ...) 引用特定对象的实例方法 特定对象::实例方法 函数式接口中被实现方法的全部参数传

  • Java静态工厂方法的实例详解

     Java静态工厂方法的实例详解 什么是静态工厂方法 对于类而言,为了让使用者获取它自身的一个实例,最常用的方法就是提供一个公有的构造器. 当然,这里要介绍的是另一种方法--静态工厂方法,一个返回类的实例的静态方法. 举个例子,Boolean的一个将基本类型boolean转为封装类的方法,valueOf: public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); } 为什么要使用静态工厂方法 那么,我们为什么要使用

  • 通过实例了解java spring使用构造器注入的原因

    这篇文章主要介绍了通过实例了解spring使用构造器注入的原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.前言 Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过将组件交由Spring的IOC容器管理,将对象的依赖关系由Spring控制,避免硬编码所造成的过度程序耦合. 二.常见的三种注入方式 2.1 field注

  • java用静态工厂代替构造函数使用方法和优缺点

    1. 形式 复制代码 代码如下: public static Boolean valueOf(boolean b) {    return b ? Boolean.TRUE : Boolean.FALSE;} 2. 优点: 可以有名称不一定要创建新对象,可以返回已有的对象可以返回子类类型的对象(例:java.util.Collections)让参数化代码变短(例:new HashMap<String,List<String>>() 改为 HashMap.newInstance()

  • java 静态工厂代替多参构造器的适用情况与优劣

    背景 假如现在你要想一个汉堡,有一个汉堡类:Hamburg.那么一般情况下你会: Hamburg hamburg = new Hamburg(); 情景一:不同参数数目的构造器 制作汉堡可以选择自定义,加肉,加菜,或者不添加,直接默认配方即可,那么会有以下几个构造器: Hamburg(); Hamburg(Meat meat); Hamburg(Meat meat,Vegetable vegetable); 当你要制作汉堡的时候,看到这么多的构造器,但是却不知道他们是什么意思,返回的汉堡到底有什

  • 如何从Java接口的角度切入静态工厂模式

    面向接口编程 接口的定义及功能 这里从java介入吧,在java中,接口是一种特殊的类,接口里面的量都是常量,接口的方法只有定义而没有实现,换句话说,接口就像一个菜单,它只会告知你我有什么菜,而并不会有实际的菜品,所以通常用接口来定义实现类的外观,根据外部应用所需要的功能,约定实现类的能力(类的功能不仅限于接口约束).通过接口,可以实现不相关类的相同功能,而不考虑这些类之间的层次关系,接口就是实现类对外的外观. 上面那样说,可能显得很装13,那千言万语化成一句人话就是:1.定义功能,对外暴露 2

  • Java 静态数据初始化的示例代码

    无论创建多少个对象,静态数据都只占用一份存储区域.static关键字不能应用于局部变量,因此它只能作用于域.如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初始值:如果它是一个对象引用,那么它的默认初始值就是null class Bowl { public Bowl(int marker) { System.out.println("Bowl(" + marker + ")"); } void f1(int marker) { Sy

  • 详解Java从工厂方法模式到 IOC/DI思想

    前言 简单工厂的本质是选择实现,说白了是由一个专门的类去负责生产我们所需要的对象,从而将对象的创建从代码中剥离出来,实现松耦合.我们来看一个例子: 我们要创建一个文件导出工具 public interface FileOper{ public Boolean exceptFile(String data); } public class XMLFileOp implment FileOper{ public Boolean exceptFile(String data){ System.out.

  • Java设计模式——工厂设计模式详解

    工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类. 工厂模式的形态 工厂模式主要用一下几种形态: 1:简单工厂(Simple Factory). 2:工厂方法(Factory Method). 3:抽象工厂(Abstract Factory). 简单工厂(Simple Factory) 又叫静态工厂,是工厂模式三中状态中结构最为简单的.主要有一个静态方法,用来接受参数,并根据参数来决定返回实现同一接口的不同类的实例.我们来看一个具体的例子: 假设一家工厂,几生产洗衣

  • Spring的实例工厂方法和静态工厂方法实例代码

    Spring的实例工厂方法和静态工厂方法都可以用来实例化bean,本文我们就来看看相关实例. 静态工厂方法:直接调用静态方法可以返回Bean的实例 package com.zhu.string.factory; import java.util.HashMap; import java.util.Map; public class StaticCarFactory { /** * 静态工厂方法:直接调用静态方法可以返回Bean的实例 * */ private static Map<String

  • Spring实战之使用静态工厂方法创建Bean操作示例

    本文实例讲述了Spring实战之使用静态工厂方法创建Bean操作.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" x

  • JAVA简单工厂模式(从现实生活角度理解代码原理)

    简单工厂模式(Simple Factory),说他简单是因为我们可以将此模式比作一个简单的民间作坊,他们只有固定的生产线生产固定的产品.也可以称他为静态工厂设计模式,类似于之前提到过静态代理设计模式,一条生产线生产一种产品(一个代理代理一种业务),为了方便大家理解,我们将KFC比作一个简单的工厂,实现代码如下: //建造接口(或者抽象类)提供食物生产方法 interface Food{ public abstract void get(); } //汉堡类(后厨生产线)来实现食物生产方法 cla

随机推荐