高清视频素材下载网站,做么做好网站运营,自己做网站练手,无人高清影视在线观看构造函数 构造代码块构造函数中应完成多少工作#xff1f; 在构造函数内部进行一些计算然后封装结果似乎是合理的。 这样#xff0c;当对象方法需要结果时#xff0c;我们将准备好它们。 听起来是个好方法#xff1f; 不#xff0c;这不对。 这是一个坏主意#xff0c;原… 构造函数 构造代码块 构造函数中应完成多少工作 在构造函数内部进行一些计算然后封装结果似乎是合理的。 这样当对象方法需要结果时我们将准备好它们。 听起来是个好方法 不这不对。 这是一个坏主意原因有一个它阻止了对象的组合并使它们不可扩展。 杀死比尔 22004由昆汀·塔伦蒂诺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 cant 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;}OverrideCacheable(forever true)public String first() {return this.origin.first();}
} 我正在使用jcabi-aspects的Cacheable批注但是您可以使用Java或其他语言可用的任何其他缓存工具例如Guava Cache public final class CachedName implements Name {private final CacheLong, 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 CallableString() {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构造函数 构造代码块