我希望创建一个有用的基本Java类,其中包含一些受保护的方法和钩子,以便可以轻松实现子类。
但是,我希望此类仅可用于派生子类,但不能作为依赖项使用。 原因是为了防止一些初级/粗心的开发人员将其代码耦合到该基类。
例如,如果我的基类名为BaseActivity.java,则任何人都可以创建自己的
public class MyNewActivity extends BaseActivity
但是没有人可以使用字段或方法签名直接引用BaseActivity,例如,不应允许这样做:
public void doSomethingOnBaseActivity(BaseActivity activity);
private BaseActivity someField;
public BaseActivity getActivity();
在Java中有什么方法可以实现这种限制吗? 也许在科特林有可能吗?
编辑: 这不是Kotlin: Can an abstract super class have an abstract constructor?的副本。 我希望防止对基类的依赖,而不仅仅是实例化。 “摘要”在这里无济于事。
答案 0 :(得分:1)
首先,让我们解决为什么。 为什么在寻找这个? 您正在寻找一种方法来防止使用者在基类上调用不需要的方法。
如果您认为自己在寻找其他东西,请再考虑一下。如果您只是想隐藏它,请三思。最终用户根本不会在乎实施细节。
如果您创建了基类,那么首先不要发布允许此操作的API 。 Clean Code中专门有一个章节。
如果您的基类扩展了另一个基类,则您会遇到麻烦。 如果要扩展而不是封装,则无法隐藏已经发布的API 。
我希望此类仅可用于派生子类,但不能作为依赖项使用。有什么办法可以在Java中完成这种限制?也许在科特林有可能吗?
不。这不是一个意见,这是设计使然。
可能有一种复杂的方法可以隐藏父类的方法,但不能在消费者与之交互的类上(扩展)。
您可能在其自己的Gradle模块中有几层基类,并且分别设置了implementation
类型依赖性,但是如果您可以扩展该类(如果可以看到它,请对其进行引用),也可以在任何地方使用
想象一下:
ConsumerActivity
扩展了ExtensibleActivity
ExtensibleActivity
扩展了BaseActivity
BaseActivity
扩展了Activity
Activity
Consumer模块只能看到“您的库模块”内部的内容。它知道ExtensibleActivity
,但看不到其任何超级类型。使用者仍然可以引用ExtensibleActivity
及其方法。副作用是因为从消费者的角度来看超类是未知的,您不能将ExtensibleActivity
的实例作为Activity
传递,因为类型系统没有知道它扩展了Activity
,因为它看不到BaseActivity
中介类型。这是消费者看到的图形:
ConsumerActivity -> ExtensibleActivity -> BaseActivity (doesn't exist) -> ??? (don't know)
这时,您只需要问自己“这应该首先扩展Activity
吗?”。
这太糟糕了。对于您不需要担心的事情,浪费了很多精力。
如果您想隐藏某些内容,请使用在继承上优先使用。将您的逻辑放入Fragment
中,或者更好地,将您的逻辑放入自定义生命周期感知组件中。这样,您就可以完全控制API 。做到这一点,这样您就不必担心从何处调用它。
为您的代码和使用手册写好的文档。
如果我选择使用不当,请允许我破坏您该死的图书馆。
您的API中有多种方法吗?大!没有人会阻止我打电话给他们。您可以在手册中写出应该如何使用它,但是最终,我正在使用您的库编写程序,如果我做错了,那是我的错。很好。
答案 1 :(得分:1)
否,这是不可能的。这个答案对所有类型都是正确的,无论抽象与否,接口或类。当您处于某个类的范围内(例如同一包),并且该类未密封时,则该范围内的每个人都可以继承它。只要您在范围内,就可以引用此类型。这就是访问修饰符的重点。允许类型的扩展但不引用它是没有意义的。这与概念相矛盾。你为什么想这么做?无论如何,您都不能删除该基类,因为这会破坏所有继承程序的代码。允许扩展但不允许引用是没有意义的。这是什么原因。也许有另一种方式可以实现您的目标。有人从类型继承的那一刻就创建了依赖关系。这种依赖关系称为继承。子类型是超类型。您无法在编译器中隐藏这一事实。
如果您想省略依赖项但重用代码或提供代码模板,则不要使用类型。您可以使用文件模板或代码生成器来生成可重复使用的代码(如代码片段)。