在 Java 中使用内部类拆分大类

我正在开发一个Android项目。我已经搜索了高和低,但我无法找出一个好的策略来拆分和打包我的代码。

我的问题是,我有使用主类变量的内部类,我无法弄清楚如何将它们解耦

我尝试过创建帮助器类,但是要么我通过构造函数传递很多变量,要么我公开我的主类,我也不想这样做

我想将每个类的最大代码行数保持在150。目前,它是278。我正在寻找解耦这些的想法,特别是如何重构类以保持抽象(变量)。最佳实践是什么?privateJava

举个例子,这是我的主要类之一,~300行。MainActivity


答案 1

编辑:

在添加 的实际代码之后,我建议如下:MainActivivty

  1. 遵循 MVC/MVP 体系结构模式。你可以找到一个链接到我在最后写的模板,但还有更多的模板 - 只需选择一个你喜欢的模板。一旦你理解了如何获取所有与UI相关的代码,方法和类都将消失。MainActivityaddButtons()CategoriesListener
  2. 真的没有必要成为一个内部类。将其作为活动之外的常规类实现。为了将数据从这个类传递回 ,只需定义一个你将要实现的侦听器接口,并传递给构造函数 - 当这个任务完成时,它将调用一个回调方法,该方法反过来将处理数据绑定到 。事实上,您在这里采用了一种非常糟糕的做法 - 通过了解实现细节,您在两者之间创建了不必要的耦合,从而违反了OOP的封装,单一责任和开放封闭原则。AllPostsFetchAsyncTaskMainActivityMainActivityMainActivity.thisMainActivityAdapterAllPostsFetchAsyncTaskMainActivity

只需实现上述两个步骤,您就可以使这种特定方式比150行代码更短。MainActivity

也就是说,您保持活动150行的长度的意图过于严格。这可以归结为这样一个事实,即如果您的 或不平凡,那么一旦实现 、 、 、 和其他标准生命周期方法,那么即使在添加自定义控制器的逻辑之前,您也可能有超过 150 行代码。ActivityFragmentonCreate()onPause()onResume()onPrepareOptionsMenu()onBackStackChanged()

现在,我完全讨厌内在的类,并试图不惜一切代价避免它们。以下清单可以作为指南,但它无论如何都不完整:

  • 切勿操作控制器/表示器中的 UI 元素(和 ) - 将这些操作封装在单独的类中。这些类是MVC / MVP视图(与Android视图相反),我将它们放入或包中。我的和倾向于在他们的源代码中有零调用。ActivitiesFragmentsAdaptersviewsmvcviewsActivitiesFragmentsfindViewById()
  • 全部放在单独的包装中(即使它们长30行)。我称此包为Adapterscontrollers.adapterscontrollers.listadapters
  • 如果需要在应用中传递一组相关数据,请定义一个 POJO(也称为值对象),并使用它来封装此数据。我通常有一个名为 的包,即使它只包含一个类。pojos
  • 定义抽象类,并放置控制器使用的任何方便逻辑。例如:我总是在 my 和 中有以下方法(或类似方法):AbstractActivityAbstractFragmentAbstractActivityAbstractFragment

    public void replaceFragment(Class <? extends Fragment> claz, boolean addToBackStack, Bundle args) { 
        // Code to replace the currently shown fragment with another one 
    }
    
  • 检查是否有任何第三方库可能在你的应用上下文中有用,并使用它们。

我的包装通常遵循以下模式:

enter image description here

我知道你写道,你已经看到了一些关于MVC的讨论,但我仍然鼓励你尝试我在这个模板/教程项目中提出的实现:https://github.com/techyourchance/android_mvc_template

希望这有帮助


答案 2

首先,根据活动的实施,您错过了一些关于活动的重要事情。

1. 只对 AsyncTask 使用静态内部类或独立类:请参阅后台任务、进度对话框、方向更改 - 是否有任何 100% 有效的解决方案?

重要的是:

步骤#2:让AsyncTask通过数据成员(通过构造函数和 setter 设置)保留活动。

步骤 #5:在 onCreate() 中,如果 getLastNonConfigurationInstance() 不为 null,请将其强制转换为 AsyncTask 类并调用 setter 以将新活动与任务关联。

您会注意到,您必须根据 Android 的生命周期方法注册和取消注册组件。这很重要要知道,始终遵循Android的生命周期!

记住这一点将始终引导您找到有关Android解耦方式的正确答案。

2. 在需要时使用数据保存类。

这里这并不真正属于活动:

// Stores the fetched dataMap
ArrayList<HashMap<String, String>> arrayList;

当您的活动记录被销毁时,例如在配置更改期间,您的所有数据都会消失,您需要再次加载所有内容。

访问和存储数据可以通过许多不同的方式完成:http://developer.android.com/guide/faq/framework.html#3

在您的情况下,这可能适用:

  • 公共静态字段/方法

    使数据可跨活动/服务访问的另一种方法是使用公共静态字段和/或方法。您可以从应用程序中的任何其他类访问这些静态字段。要共享对象,创建对象的活动将静态字段设置为指向此对象,而任何其他想要使用此对象的活动仅访问此静态字段。

还可以考虑将数据存储在数据库中或通过其他方式存储,这样即使您的应用程序被破坏,您的数据也不会消失。

3.与您的活动的沟通可以像这样完成:http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity

以相同的方式将其用于视图和视图侦听器。让一个组件管理你的视图(就像片段一样),将其注册到你的活动,使用它,在不需要的时候或生命周期需要它时取消注册它。

就像在1.中所说的那样,Android生命周期是一切的关键。

4.依赖注入是一个非常重要的主题,你可以使用它的框架(如Dagger 2或RoboGuice),也可以按照自己的方式去做。确保注入器知道依赖项(例如哪些按钮需要哪些 ClickListener 和信息,或者您的适配器需要哪些数据)并将它们绑定在一起。在始终考虑生命周期时,您将看到需要哪些接口和哪些方法以及何时调用它们。

5.不要担心代码行的数量。如果您的设计是一致的并且有意义,那么即使有500行,您也不会遇到可读性问题。顺便说一句,当正确记录代码时,它很容易超过150行代码。所以,再次担心这一点。

如果您对实现细节有任何具体问题,请提出具体问题,否则您将获得臃肿的答案。


推荐