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

时间:2015-09-24 16:03:38

标签: java

所以基本上这个线程归结为我希望一些私有方法只表示另一个方法中的代码块。我知道在Java中如何使用作用域,但有时我希望工作方式不同:

假设我的类中有一个方法 doLotsOfStuff(),它可以执行多个操作。当然,人们可以将事物分成几个方法 doThis() doThat()类型 VOID 。你遇到这种问题:

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

2) doThis() doThat()设置为私有对于同一个类中的所有其他方法仍然可见,即使我只想使用它们对于 doLotsOfStuff()。拥有一系列仅用于一次的子方法,现在会使整个类混乱。

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

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

c()可以自由地使用来自()或b()的变量,而不会在链中传递参数。

d() - / - > c()

c()不能被d()调用,因为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()!
}

有没有办法实现这一点,而不必传递一个参数?某种形式的宣言 “private void printA()取决于someMethod”?

这不是一个好的功能吗?如果没有,为什么?你会怎么做?

4 个答案:

答案 0 :(得分:2)

如果一个方法太复杂,甚至在子方法中分割它并传递参数会使类混乱,那么它可能是一个好的迹象,表明你需要委托给另一个有状态的类。

例如:

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);
}

答案 1 :(得分:2)

您正在寻找的是Closure范围界定:

Closures本身不支持

Java,而且说实话并不是很优雅。此功能在大多数动态语言中都是原生的,例如GroovyJavaScript

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

If you use final references你可以在内部类中引用它们,并且模仿具有内部类的Closure中的数据隐藏行为

Q32766010.java

public class Q32766010
{
    public static void main(final String[] args)
    {
        final Example e = new Example();
        e.doSomething(23,42);
    }

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

输出

a = 23
b = 42

这会隐藏公共界面的内部细节。

这将隐藏您正在寻找的数据/方法。它是一个 方法对象模式实现的排序可能会让新程序员绊倒,因为它在Java中并不经常使用。这种内部类使用在Python,JavaScript和Ruby等更动态的语言中很流行。

这有助于在支持代码折叠的良好IDE中整理代码。如果将IDE设置为折叠所有内部类,则会减少源 嘈杂

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

要缩小范围的几行代码几乎总是更好。范围越窄,可能产生的副作用越少,维护和调试越容易,因为由于范围狭窄,代码和代码效果的影响最小,并且显而易见。

这个习惯用法在Java中主要用于IteratorFluentBuilder模式实现,以隐藏实现的细节。以下是'UrlBuilder'的示例。

如果您有多个实现,则使用接口替代:

这种方法的工作方式相同,但如果您需要来自同一Interface的不同行为,则可以创建多个实现。

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();
    }
}

答案 2 :(得分:1)

基于Seelenvirtuose's comment
您可以创建一个“方法对象”,在其构造函数中传递所有参数,然后您可以在其任何方法中自由使用它们:

假设你有:

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);
        }
    }
}

答案 3 :(得分:0)

您提出的建议与大多数编程语言 范围 中的范例相悖。

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

分解一个大方法让它变得可理解是好的(即使你只调用一次方法),但如果你发现自己需要在原始的大方法中访问许多变量,我会质疑它是否是真的有必要打破它。

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

我在wikipedia article上发现了这个有趣的类比,我认为它适用于此。

  

想象一下,你有一个非常好的工具集 - 非常好。   现在想象一下,你决定将你的工具借给任何一个邻居   问。除非你有特殊的邻居,否则你可能会找到它   有必要修改这个政策,因为其中一些工具   最终会破碎,其他人将永远消失,无迹可寻。