【问题标题】:When to create helper methods and separate files何时创建辅助方法和分离文件
【发布时间】:2013-09-14 21:43:52
【问题描述】:

背景:我有一个大型(几百行)类,它管理基于一些原始类型数据结构的概念

long[] slist;  //list of unique patterns (related to polyominoes)
int[][][] sref;//patterns at each place [location][depth][<list of indices in slist>]

问题: 填充和更新这些数据的两种方法会很长,有少数 5-20 行任务,有些是共享的,有些是唯一的。我可能想为每个子任务创建一个辅助方法。

update(...){
    //do A
    //do B
    //do C
    //...
}
build(){
    //do D
    //do B
    //do E
    //...
}

问题是如果一个文件中有太多不相关的辅助方法,可读性并没有提高。

this question 的答案让我大部分时间都在那里。我可以在同一个包中,在它们自己的类中声明结构,并访问原始成员字段或调用相关方法。但我仍然想知道这里公认的智慧,因为这个组织并不容易想到。

您是否曾经将update()build() 函数放在各自的文件中?如果是,应该在哪里声明他们的共同任务?

【问题讨论】:

  • 您能否提供更多背景信息?是否所有任务都相关(填充数组,或实例化一堆对象,或文件读取/数据操作/文件写入或......?可能是 codereview 堆栈的一个好问题?codereview.stackexchange.com
  • @nexus_2006 有些任务是相关的,有些任务是 updatebuild 独有的。这是一个设计问题。更新以显示交叉引用的结构。这两种方法都涉及填充多维数组,但update 仅影响某些部分,例如特定“”附近最高“”的部分。

标签: java oop encapsulation helpermethods


【解决方案1】:

我强烈推荐阅读 Martin Fowler 的 Refactoring (Amazon link);它应该在每个程序员的库中,并且可以帮助您解决这种情况。我会在帖子中提及。

如果一个类的代码太多,那么通常是时候拆分这个类了。这可能需要创建具有类的成员变量(委托功能),或者可能意味着动态创建对象 (replace method with method object)。具有共同点的事物是应用继承或state/strategy pattern 的好案例。

简答

是的,您甚至可以将这些函数放在它们自己的文件中。但是,我会改为让他们上课。也许UpdaterBuilder 对象。您可以从 BuilderCommonUpdaterCommon 类继承。这些新对象将与旧对象耦合,但这没关系。您可以考虑将这些新的类集放在它们自己的包中。分层组织将有助于提高通用代码的可读性和重用性。 尝试利用继承等概念和泛型等抽象技术来为您完成工作。如果您能找到doAdoB 等之间的共同点,请将UpdateHelper 类从它们中取出,并将它们放在一个列表中。然后简单地遍历列表。

这只是众多方法中的一种

public class Updater
{
    public Updater(List<IUpdateHelper> helpers)
    {
        helpers = new ArrayList<UpdateHelper>();
        this.helpers.add(helpers);
    }
    public void update()
    {
        for (IUpdateHelper helper : helpers)
        {
            helper.performHelp();
        }
    }

    protected List<IUpdateHelper> helpers;
}

public class UpdaterCommon extends Updater
{
    public UpdaterCommon()
    {
        helpers.add(new UpdateHelperA());
        ... // Etc.
    }
}

/*
 * This uses inheritance for common helpers, but it could just as well use
 * delegation. Also, this assumes that order of invocation for each helper 
 * doesn't matter.
 */
public class UpdaterOne extends UpdaterCommon {...}

interface IUpdateHelper
{
    public void performHelp();
}
public class UpdateHelperA implements IUpdateHelper {...}

一定是replace those arrays with objects 并添加一个接口。

结束

根据我的经验,通常只需定期应用其中一些概念,就可以显着提高代码质量。如果一个包、类、方法、条件等变得不守规矩,把它分解成一个更小的单元。继续将细节功能下放到非常小的方法中,以便您可以从高层次查看代码。

【讨论】:

    【解决方案2】:

    编写同一段代码有多种不同的方法。 我喜欢把我的代码写成我可以用实际语言解释它的方式。

    例如,假设我正在创建一个人。 如果我将所有身体部位放在一个类中,阅读起来会有点混乱。

    我可以将 Head、Limbs 和 Torso 放入单独的类中,然后将它们全部放入我的 Human 类中,但即便如此,这些身体部位中的每一个都非常复杂。你可能想再分解一下。

    我可以为眼睛、鼻子、嘴巴和耳朵创建一个类,然后在您的 Head 类中引用它们。

    手指、手指关节、指甲……所有这些都可以进入 Hand 类。

    这完全取决于您的思维方式。构建完所有类后,您可以根据自己的喜好引用它们。

    为了继续这个例子,至少对我来说,我会在 Arm 类中引用 Hand 类,因为每个手臂都包含一只手(希望...)

    如果我跟注,它看起来像这样:

    Arm leftArm = new Arm();
    Arm rightArm = new Arm();
    
    leftArm.hand.makeFist();
    rightArm.hand.raiseMiddleFinger();
    

    虽然这样写会很乏味(如果你想引用手,你必须穿过手臂才能拿到它),这就是为什么我喜欢使用静态值和返回方法.这完全取决于您如何看待编程。我喜欢将编程与现实世界进行比较。

    至于辅助方法,我喜欢将它们视为操作。 如果你想做一些事情,比如“turnOnTv”或“tossBall”,那么你会想把那个方法放在受尊敬的类中。

    例如,假设您想让某人掷球。 你会希望类中的“public void tossBall()”方法有你的用户信息,所以当你调用它时,它看起来有点像

    Person personNumberOne = new Person();
    
    personNumberOne.tossBall()
    

    这只是我个人的看法。并不是说这是正确的方法,但老实说,真的没有正确的方法,看看事情可以通过多种方式完成。尽可能寻求效率总是好的,但你不想使用你也不理解的代码

    【讨论】:

      【解决方案3】:

      在这里可能有帮助的设计模式是抽象工厂模式,您可以在其中创建一个抽象类/接口,在其中定义您的辅助方法(作为抽象),并在原始 update() 和 build() 中使用此接口方法

      并为您的抽象工厂(类/接口)创建一个子类,并在这个子类中完成您的所有工作

      您可以将参数传递给将在您将创建的子类中实现它们时使用的抽象方法,以便保持事物相互连接,但也要松散耦合

      例如:

      class Client {
          private AbstractFactory factory = null;
      
          public Client(AbstractFactory factory){
              this.factory = factory;
          }
      
          void update(){
              String a = factory.getA();
              MyObject b = factory.getB(a);
              b.doSomeStuff();
              int c = factory.getC(b);
          }
      
          void build(){
              AnotherObject d = factory.getD();
              d.doMoreStuff();
          }
      }
      
      public interface AbstractFactory{
          String getA();
          MyObject getB(String a);
          int getC(MyObject b);
          AnotherObject getD();
      }
      
      
      public class Helper implements AbstractFactory{
          // implement your methods here
      }
      
      public class MyObject{ /*some helper methods here as well */}
      public class AnotherObject{ /*another helper methods here as well */}
      

      这将提供松散耦合,并且更容易分离代码,以便在您想要 修改任何东西,你不会去你的客户端类,而是会去这部分的实现类,保持你原来的客户端类不变

      并且正如 OO 原则所要求的那样......您的代码中的依赖最少,它将获得更大的灵活性,当您在代码中找到“新”这个词时,它的灵活性就会越低,请注意在客户端以class为例,几乎没有“new”关键字,这意味着它非常灵活,易于维护

      【讨论】:

        【解决方案4】:

        这个问题的另一个解决方案是模板方法模式。

        【讨论】:

        • 有人愿意评论为什么他们对问题所有者事后提供的答案投了反对票吗?
        • 投反对票的人应该伴随着回应(请注意我给了你一个upvote)。发布链接或给出“模板方法模式”是什么以及在这种情况下如何应用它的定义/示例会很有帮助。社区非常感谢人们花时间回馈并发布自己问题的答案,以便对其他人有所帮助。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多