gpt4 book ai didi

java - 保护模板模式中的钩子(Hook)

转载 作者:搜寻专家 更新时间:2023-10-31 20:00:46 24 4
gpt4 key购买 nike

我正在用 Java 实现模板模式。让我们假设下面的一段代码:

public abstract class A {

public final void work() {
doPrepare();
doWork();
}

protected abstract void doPrepare();

protected abstract void doWork();
}

public final class B extends A {

@Override
protected abstract void doPrepare() { /* do stuff here */ }

@Override
protected abstract void doWork() { /* do stuff here */ }
}

public final class Main {

public static void main(String[] args) {
B b = new B();
b.work();
}
}

我认为这是一个很容易意外拨打 b.doWork() 的问题。而不是总是打电话 b.work() .如果可能,“隐藏”钩子(Hook)的最优雅的解决方案是什么?

最佳答案

您确实在使用模板模式。您可以通过两种主要方式向外部用户“隐藏”详细信息:

1) 了解您的 access modifiers :

                   Access Levels  
Modifier | Class | Package | Subclass | World |
--------------------------------------------------
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
no modifier | Y | Y | N | N |
private | Y | N | N | N |

没有坚定的黑客通过反射来绕过这些保护措施,这些可以防止随意的编码人员意外调用最适合他们的方法。编码人员会欣赏这一点。没有人愿意使用杂乱的 API。

当前 b.doWork()protected .所以它只会在您的 main() 中可见如果您的 main()正在上课 A (不是),子类 B (不是),或在同一个包中(不清楚,您没有发布有关代码所在包的任何线索)。

这就引出了一个问题,你想保护谁不被看到 b.doWork() ?如果您正在创建的包只是您正在开发的东西,那可能还不错。如果很多人在这个包中跺脚,搞乱许多其他类,那么他们不太可能对类非常熟悉 AB .在这种情况下,您不希望所有东西都卡在每个人都可以看到的地方。这里最好只允许类和子类访问。但是没有允许子类访问而不允许包访问的修饰符。只要你是子类化 protected是你能做的最好的。考虑到这一点,不要去创建包含大量类的包。保持包裹紧密和集中。这样,大多数人将在看起来不错且简单的包之外工作。

简而言之,如果您想看 main()阻止调用 b.doWork()main()在不同的包中。
package some.other.package

public final class Main {
...
}

2) 下一条建议的值(value)对于您当前的代码将很难理解,因为它是关于解决只有在您的代码被扩展时才会出现的问题。但它确实与保护人们免于看到诸如 b.doWork() 之类的东西的想法密切相关。

What does "program to interfaces, not implementations" mean?

在您的代码中,这意味着如果 main 看起来像这样会更好:
public static void main(String[] args) {
A someALikeThingy = new B(); // <-- note use of type A
someALikeThingy.work(); //The name is silly but shows we've forgotten about B
//and know it isn't really just an A :)
}

为什么?使用类型 A有什么作用vs 类型 B事情?嗯 A更接近于成为一个界面。请注意,这里我不仅仅指的是当您使用关键字 interface 时得到的结果。 .我的意思是类型 B是类型 A 的具体实现如果我不是绝对必须针对 B 编写代码我真的宁愿不要因为谁知道什么奇怪的非 A东西 B已。这在这里很难理解,因为 main 中的代码短小精悍。另外, A 的公共(public)接口(interface)和 B并没有那么不同。他们都只有一个公共(public)方法 work() .想象一下 main()冗长而复杂,想象一下 B有各种非 A方法挂掉它。现在假设您需要创建一个类 C你想要主要处理的。看到 main 被喂食 B 是不是很令人欣慰?据 main 中的每一行都知道 B只是一些简单的 A喜欢的东西。除了 new 之后的部分这可能是真的,让您免于对 main() 做任何事情但正在更新 new .事实上,这不正是使用强类型语言有时会很好的原因吗?

<咆哮>
如果您认为甚至在 new 之后更新该部分与 B()工作太多了,你并不孤单。正是这种特殊的小痴迷给了我们 dependency injection movement这催生了一堆框架,这些框架实际上更多是关于自动化对象构造,而不是任何构造函数都可以让你做的简单注入(inject)。


更新:

我从您的评论中看到您不愿意创建小而紧凑的包装。在这种情况下,考虑放弃基于继承的模板模式,转而采用基于组合的策略模式。你仍然得到多态性。它只是不会免费发生。更多的代码编写和间接。但是即使在运行时您也可以更改状态。

这似乎违反直觉,因为现在 doWork()必须是公开的。那是怎样的保护?那么现在你可以隐藏 B完全落后甚至内部 AHandler .这是一些人性化的外观类,它保存曾经是您的模板代码但只暴露 work() . A可以只是一个 interface所以 AHandler仍然不知道它有 B .这种方法在依赖注入(inject)人群中很受欢迎,但肯定没有普遍吸引力。有些人每次都盲目地这样做,这让很多人烦恼。你可以在这里读更多关于它的内容:
Prefer composition over inheritance?

关于java - 保护模板模式中的钩子(Hook),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35529279/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com