使用Java中的Inner类拆分大类

时间:2015-06-05 07:47:00

标签: java android inner-classes packaging object-oriented-analysis

我正在开发一个Android项目。我搜索过高低,但我无法找到一个好的策略来分割和打包我的代码。

我的问题是我有使用主类变量的内部类,而我无法弄明白如何将它们分离

我试图创建帮助类,但是我要么通过构造函数传递很多变量,要么暴露我的主类,而我不想做。< / p>

我希望每个类的最大代码行保持为150.目前,它是278.我正在寻找想法来解耦这些,特别是如何重构类以保留抽象(private变量)。 Java最佳做法是什么?

例如,here是我的主要课程之一,MainActivity,约300行。

5 个答案:

答案 0 :(得分:4)

修改

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

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

    只需执行上述两个步骤,您就可以使这个特定的MainActivity方式短于150行代码。

    说,你将活动保持150行的意图太严格了。这归结为这样一个事实:如果您的ActivityFragment不是微不足道的,那么一旦您实施onCreate()onPause()onResume(),{{1} },onPrepareOptionsMenu()和其他标准生命周期方法,即使在添加自定义控制器的逻辑之前,您也可能拥有超过150行代码。

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

    • 永远不要操纵控制器/演示者(onBackStackChanged()ActivitiesFragments)中的UI元素 - 将这些操作封装在不同的类中。这些类是MVC / MVP视图(而不是Android View),我将它们放在Adaptersviews个包中。我的mvcviewsActivities的源代码往往只有Fragments次调用。
    • 将所有findViewById()放在一个单独的包中(即使它们长30行)。我称之为Adapterscontrollers.adapters
    • 如果您需要在应用中传递一组相关数据 - 定义POJO(也称为值对象)并使用它来封装此数据。我通常有一个名为controllers.listadapters的包,即使它只包含一个类。
    • 定义抽象类pojosAbstractActivity并放置控制器使用的任何便利逻辑。例如:我的AbstractFragmentAbstractActivity中总是有以下方法(或类似方法):

      AbstractFragment
    • 检查是否有任何第三方库可能在您的应用上下文中有用并使用它们。

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

    enter image description here

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

    希望这有帮助

答案 1 :(得分:3)

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

<强> 1。只有使用静态内部类或AsyncTasks的独立类:请参阅Background task, progress dialog, orientation change - is there any 100% working solution?

重要的是:

第2步:让AsyncTask通过数据成员保存在Activity上,通过构造函数和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

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

  • 公共静态字段/方法

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

另外考虑将数据存储在数据库中或通过其他方式存储,因此即使您的应用程序被销毁,您的数据也不会消失。

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

以相同的方式将它用于您的视图和查看侦听器。有一个管理你的视图的组件(像片段一样),将它注册到你的Activity,使用它,在不需要时或在生命周期需要它时注销它。

就像 1 中所述,Android生命周期是一切的关键。

<强> 4。依赖注入是一个非常重要的主题,您可以使用它的框架(如Dagger 2或RoboGuice)或以您自己的方式执行。确保您的Injector知道依赖项(比如哪些Buttons需要哪些ClickListeners和Information或您的适配器需要哪些数据)并将它们绑定在一起。在总是考虑生命周期时,您将看到需要哪些接口和方法以及何时调用它们。

<强> 5。不要担心关于代码行数。如果您的设计一致且有意义,即使有500行,您也不会遇到可读性问题。顺便说一句。在正确记录代码时,它可轻松获得超过150行代码。所以,再次担心这一点。

如果您对实施细节有任何具体问题,请询问具体问题,否则您会得到一个臃肿的答案。

答案 2 :(得分:1)

这是部分问题的答案。正如问题中所述

  

我试图创建辅助类,但是我要么通过构造函数传递很多变量

这与Telescoping constructor非常相似。所以,为了解决这个问题,我个人会使用类似于Builder Pattern的东西。

class A {
  public class B {
     public B(int x, int y, int z, int m, int n, int o){

     }
  }
}

以上案例可以修改如下。

class A {
   public class B{
     int a, int b, int c, int m, int n, int p = 0;
     public B(){
     }
     public B setA(int x){
       a = x;
       return this;
     }     
     public B setB(int x){
       b = x;
       return this;
     }
     ... and similar methods for other properties.     
   }
}

当您拥有许多属性并且您的类 - 客户端需要记住更多方法时,上述解决方案可能会使您的类看起来很长。因此,我想在上面的模式中做一些修改。为每个属性分配密钥也会使类客户端更简单。

class A {
   public class B{
     int a, int b, int c, int m, int n, int p = 0; // key for int a == "a" and for b is "b" and so on... this is our assumption.
     public B(){
     }
     public B setProperty(String key, int value){
       if(key.equals("a")){
           a = value;
       }else if(key.equals("b")){
           b = value;
       } ... and so on for other properties.
       return this;
     }     

   }
}

答案 3 :(得分:0)

如果内部类只访问字段,那么为/** new container class */ class FooBar { public Foo foo; public Bar bar; } /** nice, easy and SHORT! */ class MainActivity { private FooBar fooBar; public MainActivity() { new Ping(fooBar); new Pong(fooBar).someMethod(); } } /** successfully converted from inner class to class */ class Ping { public Ping(FooBar fooBar) { fooBar.foo = new Foo(); // Ping modifies Foo } } /** successfully converted from inner class to class */ class Pong { private Bob bob; private FooBar fooBar; public Pong (FooBar fooBar) { this.fooBar = fooBar; fooBar.bar = new Bar(); // Pong modifies bar bob = new Bob(); } public void someMethod () { fooBar.bar.setSomethingTo(Bob.getSomething()); // Pong modifies bar of Main class fooBar.foo = new Foo(fooBar.bar); // Pong assignes something to bar } } 类的所有相关字段引入一个新的Container类(当然,您也可以创建两个或三个小容器而不是一个大容器)。

然后可以将您的示例修改为:

class Foo {
    public Foo() {}
    public Foo(Bar bar) {}
}
class Bar {
    public void setSomethingTo(String something) {}
}
class Bob {
    static String getSomething() {return "Something";}
}

我使用这些类存根来获取代码编译:

MainActivity

如果内部类也在访问方法,那么您可以在接口中指定那些由MainActivity实现的方法。仅使用接口将MainActivity的实例移交给其他类。这样您就不必暴露完整的UIView,并且可以避免循环依赖。

答案 4 :(得分:-2)

拿出你的内部类,在他们的构造函数中将MainActivity的实例传递给它们。

MainActivity mainActivity;
DownloadJSON(MainActivity mainActivity) {
        super();
        mProgressDialog = new ProgressDialog(MainActivity.this);
        mProgressDialog.setCancelable(false);
        this.mainActivity=mainActivity;
    }

将mainActivity中的变量设为公共,您可以像这样访问它们:

          // Extract the metadata
         mainActivity.pageCount =Integer.parseInt(metaData.get("PAGE_COUNT"));