网站建设linux,网站建设市场多大,更换网站模板,wordpress自定义文章类型分类模板纹理和基元您显然知道什么是延迟加载 #xff0c;对吗#xff1f; 而且您无疑知道缓存 。 据我所知#xff0c;Java中没有一种优雅的方法来实现它们中的任何一个。 这是我在Cactoos原语的帮助下为自己找到的。 Matteo Garrone的《 Reality》#xff08;2012年#xff09;… 纹理和基元 您显然知道什么是延迟加载 对吗 而且您无疑知道缓存 。 据我所知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\ 。 接下来假设我们希望我们的类接受InputStream和String 。 我们想这样称呼它例如 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 IoCheckedScalarString 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(ScalarString 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 IoCheckedScalarString text;// same as above in Encrypted4Encrypted5(ScalarString 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 IoCheckedScalarString text;// same as above in Encrypted4Encrypted5(ScalarString 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纹理和基元