做网站和优化公司的宣传语,html5网站开发视频教程,网站营售,python 开发手机网站开发instanceof使用instanceof是一种代码味道。 我认为我们可能对此表示同意。 每当我看到这样的构造时#xff0c;我都会确定出现了问题。 也许有人只是在进行更改时没有注意到问题#xff1f; 也许有一个主意#xff0c;但是它太复杂了#xff0c;以至于需要太多的精力或时间… instanceof 使用instanceof是一种代码味道。 我认为我们可能对此表示同意。 每当我看到这样的构造时我都会确定出现了问题。 也许有人只是在进行更改时没有注意到问题 也许有一个主意但是它太复杂了以至于需要太多的精力或时间才能让开发人员决定不做呢 也许只是懒惰 谁知道。 事实仍然是代码演变成这种状态我们必须与之合作。 或者也许我们可以做些什么 有什么可以打开我们的扩展代码吗 今天我想向您展示如何实现这一目标。 但是首先让我解释一下为什么这个instanceof根本是个问题。 看一下代码 今天我们将讨论以下代码 public class ChangeProcessingHandler {public CodeDelta triggerProcessingChangeOf(Code code, Change change) {verifyChangeOf(code, change);if (change instanceof Refactoring) {return processRefactoring(code, (Refactoring) change);} else if (change instanceof Improvement) {return processImprovement(code, (Improvement) change);} else if (change instanceof Growth) {return processGrowth(code, (Growth) change);} else {throw new UnsuportedChangeException();}}// some more code
} 我们将尝试对其进行改进。 我试图使这段代码具有描述性但是让我简要地总结一下。 根据Change接口实现的特定类型我们选择一种准确的处理方式。 如果找不到匹配的类型我们将抛出一个异常。 现在让我们看一下这段代码有什么问题。 接口及其实现 当您查看方法的声明时您能怎么说呢 确实需要两个输入参数。 它给我们什么样的信息 我们知道依赖关系并基于它们的API我们知道如何在方法主体中与传递的对象进行交互。 在给定的例子中是真的吗 不幸的是没有。 我们正在传递一个Change实例我们希望方法的主体将取决于其接口。 但是在内部我们将实例转换为特定类型这导致依赖性增加。 这本身不是一个好的设计决策但更糟糕的是–我们在幕后增加了这个数字。 直到您不阅读方法的主体您都不会知道。 缺乏知识远比依赖数量严重得多。 新类型不是那么容易添加 假设您必须添加Change接口的新实现。 会发生什么 好吧什么都没有。 您将添加类定义并对其进行测试。 您将运行所有测试。 如果至少有一个组件或系统测试能够通过新引入的Change接口实现达到所提供的代码并且失败您将很幸运。 当没有这样的测试时问题就开始了您甚至都不知道应该改变某个地方以适应新功能。 一切都会编译您将一直工作到…… 为什么 您在代码中注意到了这个不错的UnsupportedChangeException吗 老实说它在那里只是因为设计错误。 我们拥有它有两个原因 没有它代码将无法编译。 当然如果方法无效我们可以跳过它但是在我们的示例中我们必须返回或抛出一些东西。 我们可以用其他方法代替last if-else但这不是我们想要做的。 它使我们无法添加新类型而忘记在其中添加对新引入功能的支持。 假设至少有一种测试会在这种情况下失败。 为什么我称其为错误的设计 很好使用异常来表示需要支持新功能这是对异常的滥用。 我还相信如果我们的代码通过不编译来发出信号那会更好。 这对我来说很有意义而且肯定会提供更快的反馈。 来访者进行抢救 访问者允许我们添加其他功能其实现取决于对象的特定类型。 它允许使用接口的方法。 因此我们可以避免自己检索有关特定接口的实现的信息。 首先我们需要使检索有关对象类型的信息成为可能。 为此我们必须在接口中添加一种方法该方法将允许我们传递访问者 public interface Change {void accept(Visitator visitator);
} 实现接口的每个对象的实现非常简单 public class Refactoring implements Change {Overridepublic void accept(Visitator visitator) {visitator.visit(this);}// some code
} 通过查看调用方法visit的行我们可以观察到什么 这是检索有关类型的信息的地方。 不需要instanceof也不需要强制转换。 这是我们在更好的设计支持下免费获得的东西。 这时您可能知道Visitor的界面如下所示 public interface Visitator {void visit(Refactoring refactoring);void visit(Improvement improvement);void visit(Growth growth);
} 不是那么复杂不是吗 之后我们必须从ChangeProcessingHandler类中提取一些代码到实现Visitor接口的类中 public class ChangeProcessor implements Visitator {private final Code code;public ChangeProcessor(Code code) {this.code code;}Overridepublic void visit(Refactoring refactoring) {// some code}Overridepublic void visit(Improvement improvement) {// some code}Overridepublic void visit(Growth growth) {// some code}
} 当然我们必须在正确的位置使用它 public class ChangeProcessingHandlerRefactored {public void triggerProcessingChangeOf(Code code, Change change) {verifyChangeOf(code, change);change.accept(new ChangeProcessor(code));}
}是不是更好 好的所以我们更改了原始代码。 现在让我解释一下我们获得了什么。 我们刚刚摆脱了一个例外。 不再需要它因为对新引入的实现的必要支持将通过非编译代码发出信号。 快速反馈是使用接口的结果该接口将告诉我们要完全支持所有功能还需要实现什么。 单一责任原则之所以起作用是因为“访客”界面的每个特定实现仅负责一项功能。 设计是面向行为的接口而不是面向实现的instanceof cast。 这样我们隐藏了实现细节。 设计是开放的扩展。 引入易于实现的新功能真的很容易这些功能针对特定对象而有所不同。 它不是那么完美 每个设计都是一个权衡。 您得到了一些东西但这是有代价的。 我在上段中列出了收益那么成本呢 这么多的对象 可能有人说这是使用任何设计模式的明显结果我会说是的。 但是这并不能改变以下事实随着对象数量的增加在对象之间导航变得更加困难。 将所有内容都放在一个对象中可能是一个问题但是名称不正确或杂乱无章的类可能会导致混乱。 复杂 所有这些对象都需要一个名称如果这些对象与域相关那就太好了。 在这种情况下我们最终会对我们的应用程序有了更好的了解。 但这并非总是如此。 同样我们在命名新引入的类时也必须非常小心。 所有这些都必须以不言自明的方式命名。 这并不像某些人想象的那么容易。 我的受限上下文在哪里 访客可以帮助解决与示例中出现的问题类似的问题。 但是如果有很多类似的地方您必须意识到每个访问者都在某种程度上将对象的行为放入另一个对象。 得墨meter耳定律呢 那告诉泰勒不要问吗 在使用访客解决instanceof问题之前您应该问自己这个功能是否不是对象本身的一部分 一些开发人员向我解释这是拥有小对象的一种方式。 好吧对我来说这样的解释证明了我们应该考虑绑定上下文 。 对象仍然很小它们的行为也不会泄漏给外部类。 就这样伙计们 今天就这些。 我希望您发现重新设计的想法很有用并且在阅读本文之后您的代码中的异味肯定会受到威胁。 与往常一样我鼓励您发表评论并分享您的观点和经验。 也许您更多地了解与此类变更相关的收益/问题。 翻译自: https://www.javacodegeeks.com/2016/10/really-need-instanceof.htmlinstanceof