热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

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

这篇文章主要介绍了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 静态工厂的资料请关注其它相关文章!


推荐阅读
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 在 Android 开发中,通过 Intent 启动 Activity 或 Service 时,可以使用 putExtra 方法传递数据。接收方可以通过 getIntent().getExtras() 获取这些数据。本文将介绍如何使用 RoboGuice 框架简化这一过程,特别是 @InjectExtra 注解的使用。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 本文探讨了在 ASP.NET MVC 5 中实现松耦合组件的方法。通过分离关注点,应用程序的各个组件可以更加独立且易于维护和测试。文中详细介绍了依赖项注入(DI)及其在实现松耦合中的作用。 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 探索电路与系统的起源与发展
    本文回顾了电路与系统的发展历程,从电的早期发现到现代电子器件的应用。文章不仅涵盖了基础理论和关键发明,还探讨了这一学科对计算机、人工智能及物联网等领域的深远影响。 ... [详细]
  • 科研单位信息系统中的DevOps实践与优化
    本文探讨了某科研单位通过引入云原生平台实现DevOps开发和运维一体化,显著提升了项目交付效率和产品质量。详细介绍了如何在实际项目中应用DevOps理念,解决了传统开发模式下的诸多痛点。 ... [详细]
  • 深入理解 .NET 中的中间件
    中间件是插入到应用程序请求处理管道中的组件,用于处理传入的HTTP请求和响应。它在ASP.NET Core中扮演着至关重要的角色,能够灵活地扩展和自定义应用程序的行为。 ... [详细]
  • 本文介绍如何在Spring Boot项目中集成Redis,并通过具体案例展示其配置和使用方法。包括添加依赖、配置连接信息、自定义序列化方式以及实现仓储接口。 ... [详细]
  • 本文深入探讨了SQL数据库中常见的面试问题,包括如何获取自增字段的当前值、防止SQL注入的方法、游标的作用与使用、索引的形式及其优缺点,以及事务和存储过程的概念。通过详细的解答和示例,帮助读者更好地理解和应对这些技术问题。 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
author-avatar
利盈香玟倩文怡
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有