构造函数 构造代码块_构造函数必须没有代码

构造函数 构造代码块

构造函数中应完成多少工作? 在构造函数内部进行一些计算然后封装结果似乎是合理的。 这样,当对象方法需要结果时,我们将准备好它们。 听起来是个好方法? 不,这不对。 这是一个坏主意,原因有一个:它阻止了对象的组合并使它们不可扩展。

杀死比尔2(2004)由昆汀·塔伦蒂诺(Quentin Tarantino)

杀死比尔 2(2004)由昆汀·塔伦蒂诺(Quentin Tarantino)

假设我们正在制作一个代表一个人的名字的接口:

interface Name {String first();
}

很简单,对不对? 现在,让我们尝试实现它:

public final class EnglishName implements Name {private final String name;public EnglishName(final CharSequence text) {this.parts = text.toString().split(" ", 2)[0];}@Overridepublic String first() {return this.name;}
}

这怎么了 更快吧? 它仅将名称分成几部分,然后将其封装。 然后,无论我们调用first()方法有多少次,它都将返回相同的值,并且无需再次进行拆分。 但是,这是有缺陷的想法! 让我向您展示正确的方法并说明:

public final class EnglishName implements Name {private final CharSequence text;public EnglishName(final CharSequence txt) {this.text = txt;}@Overridepublic String first() {return this.text.toString().split("", 2)[0];}
}

这是正确的设计。 我可以看到你在微笑,所以让我证明我的观点。

不过,在开始证明之前,请允许我阅读这篇文章: 可组合装饰器与命令式实用方法 。 它解释了静态方法和可组合装饰器之间的区别。 上面的第一个代码段看起来非常像一个对象,它非常接近命令式实用程序方法。 第二个例子是一个真实的对象。

在第一个示例中,我们正在滥用new运算符,并将其转换为静态方法,该方法现在和现在都为我们进行所有计算。 这就是命令式编程的目的。 在命令式编程中,我们立即执行所有计算并返回完全准备好的结果。 相反,在声明式编程中,我们尝试尽可能长时间地延迟计算。

让我们尝试使用我们的EnglishName类:

final Name name = new EnglishName(new NameInPostgreSQL(/*...*/)
);
if (/* something goes wrong */) {throw new IllegalStateException(String.format("Hi, %s, we can't proceed with your application",name.first()));
}

在此代码段的第一行中,我们只是创建一个对象的实例并将其标记为name 。 我们还不想进入数据库并从那里获取全名,将其拆分为多个部分,然后将其封装在name 。 我们只想创建一个对象的实例。 这种解析行为对我们来说将是一个副作用,在这种情况下,将减慢应用程序的速度。 如您所见,如果出现问题,我们可能只需要name.first() ,而我们需要构造一个异常对象。

我的观点是,在构造函数内部进行任何计算都是一种不好的做法,必须避免这样做,因为它们是副作用,对象所有者不要求这样做。

您可能会问,重用name期间的性能如何? 如果我们创建了EnglishName的实例,然后调用了name.first()五次,则最终将对String.split()方法进行五次调用。

为了解决这个问题,我们创建了另一个类,一个可组合的decorator ,它将帮助我们解决这个“重用”问题:

public final class CachedName implements Name {private final Name origin;public CachedName(final Name name) {this.origin = name;}@Override@Cacheable(forever = true)public String first() {return this.origin.first();}
}

我正在使用jcabi-aspects的Cacheable批注,但是您可以使用Java(或其他语言)可用的任何其他缓存工具,例如Guava Cache :

public final class CachedName implements Name {private final Cache<Long, String> cache =CacheBuilder.newBuilder().build();private final Name origin;public CachedName(final Name name) {this.origin = name;}@Overridepublic String first() {return this.cache.get(1L,new Callable<String>() {@Overridepublic String call() {return CachedName.this.origin.first();}});}
}

但是请不要使CachedName可变并且延迟加载-这是一种反模式,我之前在“ 对象应该是不可变的”中已经讨论过。

这是我们的代码现在的样子:

final Name name = new CachedName(new EnglishName(new NameInPostgreSQL(/*...*/))
);

这是一个非常原始的示例,但我希望您能理解。

在此设计中,我们基本上将对象分为两部分。 第一个知道如何从英文名称中获取名字。 第二个知道如何将计算结果缓存到内存中。 现在,作为这些类的用户,我将决定如何正确使用它们。 我将决定是否需要缓存。 这就是对象构成的全部内容。

让我重申一下,构造函数中唯一允许的语句是赋值。 如果您需要在此处放置其他内容,请开始考虑进行重构-您的课程肯定需要重新设计。

翻译自: https://www.javacodegeeks.com/2015/05/constructors-must-be-code-free.html

构造函数 构造代码块

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337918.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言按位逻辑运算符总结-与、或、非、异或

点击上方蓝字关注我&#xff0c;了解更多咨询C中有按位逻辑运算符&#xff1a;按位取反、按位与、按位或、按位异或。这4个运算符可以用于整型&#xff0c;包括char类型。按位操作针对每一个位进行操作&#xff0c;不影响左右两边的位。4个运算符的作用总结如下&#xff1a;一、…

java quartz没执行完_quartz 防止上一任务未执行完毕,下一时间点重复执行

/*** 订单监控类* 定时扫描所有待付款订单&#xff0c;超时自动取消* Created by huangbaidong* 2017/3/29.*/Componentpublic classOrderMonitorJob {ResourceprivateRedisUtil redisUtil;ResourceprivateBsdOrderService bsdOrderService;ResourceprivateBsdDFKOrderCacheMan…

th:each嵌套_难题:嵌套的computeIfAbsent

th:each嵌套总览 Java 8库在地图上有一个新方法&#xff0c;computeIfAbsent。 这是将地图转换为与键关联的对象的缓存的非常有用的方法。 但是&#xff0c;您可能没有考虑过一种组合。 如果您在内部调用computeIfAbsent会发生什么。 map.computeIfAbsent(Key.Hello, s ->…

java图论_玩转算法系列--图论精讲 面试升职必备(Java版)

第1章 和bobo老师一起&#xff0c;玩转图论算法欢迎大家来到我的新课程&#xff1a;《玩转图论算法》。在这个课程中&#xff0c;我们将一起完整学习图论领域的经典算法&#xff0c;培养大家的图论建模能力。通过这个课程的学习&#xff0c;你将能够真正地&#xff0c;玩转图论…

C语言的本质——位运算

点击上方蓝字关注我&#xff0c;了解更多咨询位运算是指按二进制进行的运算。在系统软件中&#xff0c;常常需要处理二进制位的问题。C语言提供了6个位操作运算符。这些运算符只能用于整型操作数&#xff0c;即只能用于带符号或无符号的char,short,int与long类型。C语言提供的位…

servlet异步_关于Servlet和异步Servlet

servlet异步Servlet API是Java EE标准的一部分&#xff0c;自1998年正式发布2.1规范以来&#xff0c;一直是基于Java的企业体系结构的重要组成部分。 它是一种自以为是的API&#xff0c;用于服务围绕一些基本概念构建的请求/响应协议&#xff1a; 兼容的容器 &#xff0c;这是…

Java创新型模式_java设计模式--创建型模式(一)

2016-04-24 10:10:34创建型模式&#xff1a;工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式注意&#xff1a;工厂模式可以分为三类&#xff1a; 1)简单工厂模式(Simple Factory) 2)工厂方法模式(Factory Method) 3)抽象工厂模式(Abstract Factory)这三种模式从上…

原来这就是C语言的基本结构—循环结构?!

点击上方蓝字关注我&#xff0c;了解更多咨询今天我们就着重说说循环结构。循环结构分为三种&#xff0c;分别是for、while、dowhile;我们首先说第一种&#xff1a;for循环..他的代码格式为&#xff1a;for(判断的数值初始化;判断条件;改变判断数值大小){循环语句块&#xff1b…

可视化编码_编码:可视化位图

可视化编码在过去的一个月左右的时间里&#xff0c;我每天花费一些时间来阅读Neo4j代码库的新部分&#xff0c;以使其更加熟悉&#xff0c;而我最喜欢的类之一是Bits类&#xff0c;该类可以完成所有底层工作&#xff0c;到磁盘。 特别是&#xff0c;我喜欢它的toString方法&am…

java count 在哪一类里_java 5线程中 Semaphore信号灯,CyclicBarrier类,CountDownLatch计数器以及Exchanger类使用...

先来讲解一下Semaphore信号灯的作用:可以维护当前访问自身的线程个数&#xff0c;并提供了同步机制&#xff0c;使用semaphore可以控制同时访问资源的线程个数例如&#xff0c;实现一个文件允许的并发访问数。请看下面的演示代码:1 public classSemaphoreTest2 {3 public stati…

spring aop示例_Spring查找方法示例

spring aop示例当一个bean依赖于另一个bean时&#xff0c;我们使用setter属性或通过构造函数注入bean。 getter方法将向我们返回已设置的引用&#xff0c;但是假设您每次调用getter方法时都想要一个依赖bean的新实例&#xff0c;那么您可能将不得不采用另一种方法。 在本文中…

java hive查询_java程序调用hive查询的一个异常

最近在java程序中调用hive做查询时&#xff0c;碰到一个异常&#xff0c;被困扰了许久&#xff0c;经过几番调试&#xff0c;逐步把问题定位清楚。在异常描述前先给出异常信息&#xff1a;java.sql.SQLException: Error while processing statement: FAILED: Execution Error, …

C/C++入门易错点及常用小技巧

点击上方蓝字关注我&#xff0c;了解更多咨询C语言诞生至今已有30多个年头了&#xff0c;主要集中在需要运行效率比较高的行业&#xff0c;比如现在的游戏开发以及高效服务器等等。C学习难度比其它语言都要高&#xff0c;这是不可否认的&#xff0c;其学习难度主要在于它的复杂…

quasar_Quasar和Akka –比较

quasaractor模型是用于容错和高度可扩展系统的设计模式。 角色是独立的工作程序模块&#xff0c;它们仅通过消息传递与其他角色进行通信&#xff0c;可以与其他角色隔离而失败&#xff0c;但是可以监视其他角色的故障并在发生这种情况时采取一些恢复措施。 角色是简单&#xff…

java 文件封装_Java 封装

在面向对象程式设计方法中&#xff0c;封装(英语&#xff1a;Encapsulation)是指&#xff0c;一种将抽象性函式接口的实作细节部份包装、隐藏起来的方法。封装可以被认为是一个保护屏障&#xff0c;防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据&am…

什么是自定义函数?精简回答

点击上方蓝字关注我&#xff0c;了解更多咨询1、自定义函数是程序员根据所要完成的功能&#xff0c;自己写出的源代码实现该功能。2、自定义函数和库函数一样&#xff0c;具有函数名&#xff0c;返回值类型&#xff0c;和函数参数。示例1&#xff1a;写一个函数找出两整数的值。…

为什么awt_为AWT的机器人创建DSL

为什么awtJava SDK附带了java.awt.Robot类&#xff0c;该类允许键盘和鼠标输入的自动化以及屏幕捕获的创建。 当您要编写一个模拟用户输入的小型测试应用程序时&#xff0c;或者只想自动化一些重复文本的输入时&#xff0c;此功能非常有用。 但是您不想每次都编写一个完整的Jav…

C++ 创建文件夹的几种方式汇总确定不来看看???

点击上方蓝字关注我&#xff0c;了解更多咨询1、使用 system() 调用 dos 命令。2、使用头文件 direct.h 中的 access 和 mkdir 函数。关于 direct.h 我觉得 维基百科 上介绍的不错3、调用 Windows API 函数。4、调用 MFC 封装好的接口函数。不推荐此方法&#xff0c;出错的话会…

java语言使用箭头键画线_Java:使用带箭头键的按键

按向下箭头键启动程序,首先观察字符串.这里看一下这个示例程序&#xff1a;import java.awt.*;import java.awt.event.*;import javax.swing.*;public class KeyBindingExample{private void createAndDisplayGUI(){JFrame frame new JFrame("Key Binding Example")…

et游戏自动翻译工具_ET的异常翻译

et游戏自动翻译工具前段时间&#xff0c;我写了一篇有关用AspectJ进行异常转换的小博客文章。 在此博客文章中&#xff0c;我们将看到如何使用ET及其更轻松的Java 8方法来实现相同的目的。 动机 异常转换&#xff08;或异常转换&#xff09;是将一种类型的异常转换为另一种类型…