纹理和基元

您显然知道什么是延迟加载 ,对吗? 而且您无疑知道缓存 。 据我所知,Java中没有一种优雅的方法来实现它们中的任何一个。 这是我在Cactoos原语的帮助下为自己找到的。

Matteo Garrone的《 Reality》(2012年)

假设我们需要一个可以加密某些文本的对象。 以一种更加面向对象的方式讲,它将封装文本并成为其加密形式。 这是我们将如何使用它( 首先创建测试 ):

interface Encrypted {String asString() throws IOException;
}
Encrypted enc = new EncryptedX("Hello, world!");
System.out.println(enc.asString());

现在,让我们以一种非常原始的方式用一个主要的构造函数来实现它。 加密机制只会在传入数据中的每个字节上加上+1 ,并且会假设加密不会破坏任何内容(一个非常愚蠢的假设,但对于本示例而言,它将起作用):

class Encrypted1 implements Encrypted {private final String text;Encrypted1(String txt) {this.data = txt;}@Overridepublic String asString() {final byte in = this.text.getBytes();final byte[] out = new byte[in.length];for (int i = 0; i < in.length; ++i) {out[i] = (byte) (in[i] + 1);}return new String(out);}
}

到目前为止看起来正确吗? 我测试了它 ,而且效果很好。 如果输入是"Hello, world!" ,输出将为"Ifmmp-!xpsme\""

接下来,假设我们希望我们的类接受InputStreamString 。 我们想这样称呼它,例如:

Encrypted enc = new Encrypted2(new FileInputStream("/tmp/hello.txt")
);
System.out.println(enc.toString());

这是最明显的实现,具有两个主要的构造函数(同样,实现是原始的,但是可以工作):

class Encrypted2 implements Encrypted {private final String text;Encrypted2(InputStream input) throws IOException {ByteArrayOutputStream baos =new ByteArrayOutputStream();while (true) {int one = input.read();if (one < 0) {break;}baos.write(one);}this.data = new String(baos.toByteArray());}Encrypted2(String txt) {this.text = txt;}// asString() is exactly the same as in Encrypted1
}

从技术上讲,它是可行的,但是流读取是在构造函数内部进行的,这是不正确的做法 。 主要构造函数只能执行属性分配,而次要构造函数只能创建新对象。

让我们尝试重构并引入延迟加载:

class Encrypted3 {private String text;private final InputStream input;Encrypted3(InputStream stream) {this.text = null;this.input = stream;}Encrypted3(String txt) {this.text = txt;this.input = null;}@Overridepublic String asString() throws IOException {if (this.text == null) {ByteArrayOutputStream baos =new ByteArrayOutputStream();while (true) {int one = input.read();if (one < 0) {break;}baos.write(one);}this.text = new String(baos.toByteArray());}final byte in = this.text.getBytes();final byte[] out = new byte[in.length];for (int i = 0; i < in.length; ++i) {out[i] = (byte) (in[i] + 1);}return new String(out);}
}

效果很好,但看起来很丑。 最丑陋的部分当然是这两行:

this.text = null;
this.input = null;

它们使对象可变,并且使用NULL 。 丑陋,相信我。 不幸的是,延迟加载和NULL引用总是在经典示例中并存 。 但是,有一种更好的方法来实现它。 让我们重构类,这次使用Cactoos的 Scalar

class Encrypted4 implements Encrypted {private final IoCheckedScalar<String> text;Encrypted4(InputStream stream) {this(() -> {ByteArrayOutputStream baos =new ByteArrayOutputStream();while (true) {int one = stream.read();if (one < 0) {break;}baos.write(one);}return new String(baos.toByteArray());});}Encrypted4(String txt) {this(() -> txt);}Encrypted4(Scalar<String> source) {this.text = new IoCheckedScalar<>(source);}@Overridepublic String asString() throws IOException {final byte[] in = this.text.value().getBytes();final byte[] out = new byte[in.length];for (int i = 0; i < in.length; ++i) {out[i] = (byte) (in[i] + 1);}return new String(out);}

现在看起来好多了。 首先,只有一个主要构造函数和两个次要构造函数。 其次,对象是不可变的 。 第三,还有很多改进的余地:我们可以添加更多的构造函数来接受其他数据源,例如File或byte数组。

简而言之,应该以“惰性”方式加载的属性在对象内部表示为“功能”(Java 8中的lambda表达式 )。 在我们触摸该属性之前,不会加载该属性。 一旦我们需要使用它,函数就会被执行并得到结果。

这段代码有一个问题。 每当我们调用asString() ,它将读取输入流,这显然是行不通的,因为只有第一次流才会有数据。 在每个后续调用中,流都将为空。 因此,我们需要确保this.text.value()仅执行一次封装的Scalar 。 所有以后的调用都必须返回以前计算的值。 因此,我们需要对其进行缓存 。 方法如下:

class Encrypted5 implements Encrypted {private final IoCheckedScalar<String> text;// same as above in Encrypted4Encrypted5(Scalar<String> source) {this.data = new IoCheckedScalar<>(new StickyScalar<>(source));}// same as above in Encrypted4

StickyScalar将确保仅对其方法value()的第一次调用将传递给封装的Scalar 。 所有其他呼叫将接收第一个呼叫的结果。

要解决的最后一个问题是关于并发性。 我们上面的代码不是线程安全的。 如果我创建Encrypted5的实例并将其传递给同时调用asString()两个线程,则结果将是不可预测的,这仅仅是因为StickyScalar不是线程安全的。 不过,还有另一个可以帮助我们的原语,称为SyncScalar

class Encrypted5 implements Encrypted {private final IoCheckedScalar<String> text;// same as above in Encrypted4Encrypted5(Scalar<String> source) {this.data = new IoCheckedScalar<>(new SyncScalar<>(new StickyScalar<>(source)));}// same as above in Encrypted4

现在我们很安全,设计优雅。 它包括延迟加载和缓存。

我现在在许多项目中都使用这种方法,而且看起来很方便,清晰且面向对象。

您可能还会发现这些相关的帖子很有趣: 为什么InputStream设计错误 ; 尝试。 最后。 如果。 不。 空值。 ; 每个私有静态方法都是新类的候选人 ; 我将如何重新设计equals() ; 对象行为不可配置 ;

翻译自: https://www.javacodegeeks.com/2017/10/lazy-loading-caching-via-sticky-cactoos-primitives.html

纹理和基元

纹理和基元_通过粘性仙人掌基元进行延迟加载和缓存相关推荐

  1. 通过粘性仙人掌基元进行延迟加载和缓存

    您显然知道什么是延迟加载 ,对吗? 而且您无疑知道缓存 . 据我所知,Java中没有一种优雅的方法来实现它们中的任何一个. 这是我在Cactoos原语的帮助下为自己找到的. Matteo Garron ...

  2. 几何基元_.NET异步协调基元中的两种技术比较

    几何基元 Last week in my post on updating my Windows Phone 7 application to Windows 8 I shared some code ...

  3. 运动基元_发现大量Java基元集合处理

    运动基元 在阅读博客文章5减少Java垃圾收集开销的技巧时 ,我想起了一个名为Trove的小型Java收集库,该库"为Java提供了高速的常规和原始收集". 我对将Trove应用到 ...

  4. BZOJ_1778_[Usaco2010 Hol]Dotp 驱逐猪猡_概率DP+高斯消元

    BZOJ_1778_[Usaco2010 Hol]Dotp 驱逐猪猡_概率DP+高斯消元 题意: 奶牛们建立了一个随机化的臭气炸弹来驱逐猪猡.猪猡的文明包含1到N (2 <= N <= 3 ...

  5. 小肩膀POST+JS第三期(价值1000元)_高清带源码

    小肩膀POST+JS第三期(价值1000元)_高清带源码 .课程整体介绍 2.谷歌开发者工具 3.火狐firebug组件 4.火狐开发者工具 5.HTTP Analyzer V7 6.Fiddler ...

  6. 2 shell 锂基脂_壬二酸和癸二酸制备的复合锂基脂到底有那些差别!

    2019年12月21-22日 深圳<润滑脂生产技术培训班>烃基脂,钙基脂,锂基脂,复合锂基脂.铝基脂,复合铝,磺酸钙脂等润滑脂的生产配方设计及生产工艺和流程,专家现场答疑,报名咨询:189 ...

  7. 六元均匀直线阵的各元间距为_实验二 均匀直线阵

    实验二 均匀直线阵 一.实验目的: 通过 MATLAB 编程,了解均匀直线阵的辐射特性,熟悉影响天线阵辐射的各种因素及其 产生的影响. 二.实验环境: MATLAB 软件 三.实验原理: 单个天线的方 ...

  8. 井通swtc能不能涨到2元_买一支2块到3块之间的股票,买几十万股吗?这样操作效果怎么样?...

    有很多新股民有一种看法,认为高价股风险很大,那么可不可以买2到3元的低价股,是不是风险就很小,以后上涨的力度就会很大? 这是很多股民都存在的一个误区,也是很多股市的所谓高手的误导,他们说:只要买入低价 ...

  9. python123百钱买百鸡_求解百钱买百鸡问题。假设大鸡 5 元一只,中鸡 3 元一只,小鸡 1 元三只,现有 100 元钱想买 100 只鸡,有多少种买法?截图代码和运行结果_学小易找答案...

    [填空题]表达式 'apple.peach,banana,pear'.find('ppp') 的值为 ________ . [填空题]已知 x = '123' 和 y = '456' ,那么表达式 x ...

最新文章

  1. 学习在Unity中创建一个动作RPG游戏
  2. 微信公众号开发用书php,php微信公众号开发(3)php实现简单微信文本通讯
  3. 语言 上课点名 缺勤_主播日记5 | “云端”传递的C语言程序设计实验课
  4. 【MPI程序】向量乘法,向量点积(高性能计算)
  5. 服务器系统自带虚拟机吗,现在所说的服务器虚拟化,也就是在vmware虚拟机上搭建的吗...
  6. python 抓取微博评论破亿_如果利用Python分析14亿条数据!资深程序员手把手教你!过亿级!...
  7. Android studio 使用心得(八)----测试程序单元测试
  8. 华为鸿蒙11什么时候发布,原创 华为EMUI11正式发布,今年12月可升级为鸿蒙OS2.0国产操作系统...
  9. java 定时任务 quartz 时间表达式Cron总结
  10. Python之面向对象-类与 类之间的关系
  11. springboot毕设项目网上商城系统8l44b(java+VUE+Mybatis+Maven+Mysql)
  12. 【毕业设计】 基于单片机的移动共享充电宝设计与实现 - 物联网嵌入式 stm32 c51
  13. 目标窗口检测算法-NMS非极大值抑制
  14. 解密Uber自动驾驶系统,警方披露撞人案细节
  15. schedule定时任务
  16. apt查看安装包可用版本号
  17. IDEA绿色护眼色设置(含代码区 项目结构区 运行区)
  18. HBase二级索引的设计与应用(详解)
  19. 硬件nat关闭还是开启_NAT(Network Address Translation)网络地址转换技术详解
  20. 服务器显示free怎么回事,free云服务器

热门文章

  1. Zju2112 Dynamic Rankings(树状数组套可持久化权值线段树)
  2. ybtoj洛谷P3268:圆的异或并(扫描线)
  3. 理解至上:二叉堆与优先队列详细用法
  4. P1197-星球大战【并查集,图论】
  5. codeforces gym-101755 I-Guess the Tree 交互题、分治、树的直径
  6. Dubbo(九)之注解配置
  7. Sentinel(十二)之实时监控
  8. vue-beauty 的v-data-table数据单元不换行
  9. 若依部署上线之后验证码不显示的解决方法之一
  10. 加油四班!加油佟穆!我们的征途是星辰大海!!!