【问题标题】:Is it bad practice to divide responsibilities by extending BaseActivites?通过扩展 BaseActivites 来划分职责是不好的做法吗?
【发布时间】:2017-10-19 10:36:39
【问题描述】:

我划分 MainActivity 的职责,并尝试通过扩展 BaseActivities 来保持它的清洁和可读性,例如 MainActivity 扩展 AdBaseActivity 扩展 LocationBaseActivity 扩展 FullScreenActivity 扩展 Activity。

每个活动只关心它们被命名为做什么,同时保持 MainActivity 设置布局和视图并运行任务的主对象,例如 GameSurfaceView 或它应该运行的主类。这种关于耦合和内聚、难以测试或任何其他设计原则方面的不良编程实践?

是否使用一个类,例如 LocationController 与所有必需的生命周期方法并实例化或与依赖注入一起使用,是否比扩展 BaseActivities 更好?

我想知道当需要权限并且应该插入 DialogFragment 或任何其他视图,或者返回另一个 Activity 的结果时,如何使用 Activity 所需的回调来维护 Manager 类?这些管理器类可以是其他类的成员,对 Activity 有更深的引用可能会导致内存泄漏,如果这种情况只能 当管理器类处于阻止 Activity 引用不被释放的特定状态时发生。

【问题讨论】:

    标签: java android inheritance


    【解决方案1】:

    TLDR;

    是和不是!

    继承和所有OOP 原则对于可读性和代码管理非常有效,但由于您正在开发移动应用程序,太多的类可能会降低内存和性能。


    我了解您要做什么以及为什么。不久前我在编写一个相当大的Android 应用程序时遇到了同样的问题。

    由于它基本上是一个带有 4 个 Fragments 的单个 Activity 应用程序,因此我的 MainActivity 中的代码过多,即使将一些代码委托给我的 Fragments。

    然后我更改了我的 MainActivity 并通过组合使其拥有以下 Manager 类:

    • LocationManager
    • ApiVendorManager
    • UIManager
    • BackgroundJobManager
    • AppFunctionalityManager
    • StageTransitionManager
    • ...

    每个包含 800+ 行代码和生命周期回调(onCreate()、onPause()、...)。

    在那之后,我的MainActivity 非常干净和井井有条,我为自己感到自豪,但我注意到性能急剧下降。

    然后我偶然发现了这个documentation page,上面写着:

    但是,抽象需要付出巨大的代价:通常它们需要执行相当多的代码,需要更多的时间和更多的 RAM 才能将该代码映射到内存中。

    我最后所做的是通过仅维持 4 个Managers 在抽象和性能之间找到一些平衡。

    我会说:继续抽象,直到发现性能问题。此时您应该考虑限制继承和组合,甚至可能重新合并一些以前扩展的类。

    同样的原则也适用于扩展Activity 类。

    【讨论】:

    • 老实说,我更喜欢组合而不是继承,为位置、传感器、蓝牙等创建管理器类。但是这个管理器引用了 Activity 并且这些管理器类成为其他类的一部分,从而产生更深入的引用,不是这么差?此外,您需要为这些应该由 Activity 实现的类声明回调,这会导致我的活动带有太多回调。 Activity 类的角色既适用于视图,也适用于 onPermissionResult() 方法等方法,这让我很难维护它。
    • 这正是我所做的。我有一个接口BaseManager 声明我所有的方法(nextStage(),...)和生命周期回调(onCreate(),...)。我确保我的MainActivity 正在调用所有Managers 子方法。例如:onResume()必须在所有 managers 中调用 onResume() 方法。然后Managers 引用了Activity。你所做的,通过在类之间拆分职责,通过组合或继承,是非常好的实践。我警告过你的问题是,在移动世界中你可能会面临硬件限制。如果那是你的担心。 @FatihOzcan
    • 我真正担心的是当项目变大时无法维护它们,对这个管理器有更深入的引用,而这些管理器有其他对象可能会导致保留对 Activity/context 或其他可能导致内存泄漏的类的引用.性能更明显并且可以解决,但可能存在可能导致内存泄漏的对象状态。我也希望这些类可以重复使用。
    • 正如我所说,只是不要使用太多的复合类。每个Manager 都应遵循Activity 释放资源的准则:在onResume() 或onDelete() 方法中。不要害怕存储对您的Activity 的引用。一个很好的无泄漏示例是 Fragment 中著名的 MapView。它不会导致任何内存泄漏。只要确保所有者的生命周期方法也调用子类各自的方法。如果您担心内存泄漏,可以查看 Java 的 WeakReference<T>。
    【解决方案2】:

    这取决于目标项目。如果您想从可重用性中受益。那么这不是一个好习惯,因为拆分依赖项并不容易。但如果你不打算再次重用代码并且你的东西相对较小..那么它可能没那么糟糕,有时它是继承风格管理逻辑的唯一方法。

    但还有另一种方式……作曲!

    见:Difference between Inheritance and Composition

    组合是has-a 关系,而继承是is-a。其实组合是继承繁重时的出口。

    使用像 Dagger 这样的依赖注入器来应用 composition 会在可读性、可重用性和可扩展性方面提供高质量的代码。

    【讨论】:

    • 我更喜欢组合而不是继承,这实际上就是我问的原因,但是 Activity 类同时承担了视图和控制器角色,这让我很难掌握正确的模型。为什么 Activity 的继承不利于 resubility,您始终可以删除和添加专注于他们需要完成的任务的独立 Activity。在我编写的示例中,您可以轻松更改扩展顺序、删除或添加任何 BaseActivity,例如 SensorBaseActivity 或 BluetoothBaseActivity。
    • 考虑你有一个大层作为超类,即 BT。你需要为它设置基类。继承不能轻易做到这一点。还有一件事,继承导致展开所有超类中的所有方法,但组合会将这些方法分组到它的类型下。所以它很容易识别并且不会被覆盖。最后一件事与测试和定制有关。您可以使用组合轻松交换模块。使用模拟或自定义模块。继承是不可能的。这并不意味着继承是邪恶的☺。只是不要在那里加载太多变体代码。
    【解决方案3】:

    耦合是 OOP 的基本关键,不存在“通过耦合做错事”这样的事情。您希望尽可能多地进行封装,并且每次您感觉要再次编写相同的代码时,请改用耦合。

    另请参阅此问题以获取有关您的主题的更多说明:Is there such thing as too many classes?

    【讨论】:

    • 我知道耦合和内聚是软件开发过程的一部分,但我希望将其保持在最低限度以实现可重用性和可维护性。我的问题不是关于有太多的类,我实际上非常喜欢太多的类来分离职责并避免创建对一切负责的上帝对象。遵守 GRASP 和 SOLID 原则是很好的,但是带有所有回调的 Activites,尤其是 onResultActivity() 和 onPermissionResult() 方法以及视图渗透使您的类完全抽象。我想知道应该是什么样的结构和平衡。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 2015-05-31
    相关资源
    最近更新 更多