Java 如何有效地将方法划分为子方法?

Java 如何有效地将方法划分为子方法?,java,Java,因此,这个线程的基本结论是,我希望一些私有方法只表示另一个方法中的代码块。我知道范围界定在Java中是如何工作的,但有时我希望事情能以不同的方式工作: 假设在我的类中有一个方法doLotsOfStuff(),它可以做多种事情。很自然地,我们会将这些东西分成几个类型为VOID的方法doThis()和doThat()。您会遇到此类问题: 1) 在doThis()和doThat()中的dolotsoftuff()中定义的任何数据上,如果不首先传递所需的所有必要参数,我将无法再操作这些数据,这不会使它们

因此,这个线程的基本结论是,我希望一些私有方法只表示另一个方法中的代码块。我知道范围界定在Java中是如何工作的,但有时我希望事情能以不同的方式工作:

假设在我的类中有一个方法doLotsOfStuff(),它可以做多种事情。很自然地,我们会将这些东西分成几个类型为VOID的方法doThis()和doThat()。您会遇到此类问题:

1) 在doThis()和doThat()中的dolotsoftuff()中定义的任何数据上,如果不首先传递所需的所有必要参数,我将无法再操作这些数据,这不会使它们无效!例如doThis(int dolotsofstfulsint)这意味着如果我想要一个调用链,那么必须在一行参数中传递相同的变量。。这就导致了:

2) 设置为private的doThis()和doThat()对于同一类中的所有其他方法仍然可见,尽管我只想将它们用于doLotsOfStuff()。拥有一长串只打算一次使用的子方法将使整个类变得混乱

以下是我希望存在的东西: a、 b、c、d是同一类中的私有方法。->表示对方法的调用

a()->b()->c()

c()可以自由使用a()或b()中的变量,而无需在整个链中传递参数

d()-/->c()

d()不能调用c(),因为c()只对a()及其任何后续调用方“本地”

举个简单的例子:

private void someMethod()
{
    char a = 'a';
    printA();
}


private void printA() {
    System.out.println(a);  //a cannot resolve, but I don't want to pass it as an argument from someMethod()!
}
有没有一种方法可以实现这一点,而不必通过一个参数?某种形式的声明 “私有void printA()依赖于someMethod”


这不是一个很好的功能吗?若否,原因为何?您将如何做到这一点?

您的建议与大多数称为范围的编程语言中的范例背道而驰

该方法存在的原因是封装了较大程序的一部分功能,使其易于理解和重用

分解一个大方法以使其易于理解是很好的(即使只调用一次该方法),但是如果您发现自己需要访问原始大方法中的许多变量,我会质疑是否真的有必要分解它

如果语言允许方法访问其他方法中的变量,那么跟踪程序中发生的事情将成为一场噩梦

我在网上找到了这个有趣的类比,我认为它在这里很适用

想象一下,你有一个非常好的工具集合非常好。 现在想象一下,你决定把你的工具借给任何一个 问。除非你有特别的邻居,否则你可能会找到它 最终需要修改此策略,因为其中一些工具 将以破碎而告终,而其他人将永远消失而无影无踪


如果一个方法非常复杂,即使将其拆分为子方法和传递参数也会使类变得混乱,那么这可能是一个好迹象,表明您需要委托给另一个有状态类

例如:

private void someMethod() {
    ComplexPrinter printer = ComplexPrinter('a');
    printer.foo();
    printer.bar();
    printer.baz();
}
或者至少,为了避免向每个方法传递太多参数,将它们存储在单个上下文对象中:

private void someMethod() {
    PrintContext context = PrintContext('a', 'b', 'c', 'd', 'e');
    foo(context);
    bar(context);
    baz(context);
}
您正在寻找的内容称为范围界定:
闭包
Java
中不受本机支持,老实说,模仿起来也不是很优雅。这种能力在大多数动态语言中都是固有的,比如
Groovy
JavaScript

A捕获其定义范围内的变量

您可以在内部类中引用它们,并用内部类模拟
闭包中的数据隐藏行为

输出 这会对公共界面隐藏内部详细信息。 这将完成您要查找的数据/方法隐藏。这是一个 方法对象模式实现排序,可能会绊倒新程序员,因为它在Java中不经常使用。这种内部类的使用在Python、JavaScript和Ruby等动态语言中非常普遍

这有助于在支持代码折叠的良好IDE中分离代码。如果您将IDE设置为折叠所有内部类,则会减少源代码 吵闹

多行代码并不总是坏事,如果你能更容易地使用Intellij IDEA这样的工具自动重构一些东西,那么多行代码就更好了,因为它可以自动维护

多写几行代码来缩小范围几乎总是更好的。范围越窄,可能产生的副作用就越少,维护和调试就越容易,因为由于范围狭窄,代码的影响和代码的影响最小,并且非常明显

这个习惯用法在Java中主要用于
Iterator
FluentBuilder
模式实现,以隐藏实现的细节。这里有一个例子

如果您有多个实现,可选择使用接口: 这是同样的工作方式,但是如果您需要同一
接口的不同行为
,则可以创建多个实现

public static class Example
{
    interface ClosureLikeThing
    {
        public ClosureLikeThing doThis();

        public ClosureLikeThing doThat();
    }

    public void doSomething(final int a, final int b)
    {
        new ClosureLikeThing()
        {
            @Override
            public ClosureLikeThing doThis()
            {
                System.out.println("a = " + a);
                return this;
            }

            @Override
            public ClosureLikeThing doThat()
            {
                System.out.println("b = " + b);
                return this;
            }
        }.doThis().doThat();
    }
}
基于:
您可以创建一个“方法对象”,向其构造函数传递所有参数,然后可以在其任何方法中自由使用这些参数:

假设你有:

public class SomeClass
{
    private void someMethod()
    {
        char a = 'a';
        char b = 'b';
        char c = 'c';
        System.out.println(a);
        /* Lots of code here */
        System.out.println(b);
        /* More lots of more code here */
        System.out.println(c);
    }
}
你可以把它变成:

public class SomeClass
{
    private void someMethod()
    {
        LongMethod lm = new LongMethod('a', 'b', 'c');
        lm.printA();
        lm.printB();
        lm.printC();
    }

    private static class LongMethod
    {
        private char a;
        private char b;
        private char c;

        public LongMethod(char a, char b, char c)
        {
            this.a = a;
            this.b = b;
            this.c = c;
        }

        public void printA()
        {
            /* A third of a lot of code here */
            System.out.println(a);
        }

        public void printB()
        {
            /* A third of a lot of code here */
            System.out.println(b);
        }

        public void printC()
        {
            /* A third of a lot of code here */
            System.out.println(c);
        }
    }
}

也许a适合您的需要?我不是JVM方面的专家,但我认为在执行时,
printA(inta)
vs
printA()
使用成员变量的效率几乎没有差别。当谈到可读性和减少杂乱时,考虑使用一个内部类。我想您已经知道了这一点,但是如果您想避免将变量“a”传递给printA(),您应该
public class SomeClass
{
    private void someMethod()
    {
        char a = 'a';
        char b = 'b';
        char c = 'c';
        System.out.println(a);
        /* Lots of code here */
        System.out.println(b);
        /* More lots of more code here */
        System.out.println(c);
    }
}
public class SomeClass
{
    private void someMethod()
    {
        LongMethod lm = new LongMethod('a', 'b', 'c');
        lm.printA();
        lm.printB();
        lm.printC();
    }

    private static class LongMethod
    {
        private char a;
        private char b;
        private char c;

        public LongMethod(char a, char b, char c)
        {
            this.a = a;
            this.b = b;
            this.c = c;
        }

        public void printA()
        {
            /* A third of a lot of code here */
            System.out.println(a);
        }

        public void printB()
        {
            /* A third of a lot of code here */
            System.out.println(b);
        }

        public void printC()
        {
            /* A third of a lot of code here */
            System.out.println(c);
        }
    }
}