驯服不可变数据管道的冗长

时间:2018-01-09 18:39:17

标签: java

我有一个CSV转换类。它的工作是捣乱价值并产生少量产出。 CSV行有大约30列。我通过不可变对象建模:

In(i1, i2, ..., iM)
OutA(a1, a2, ..., aN)
OutB(b1, b2, ..., bO)
...
OutK(k1, k2, ..., kP)
OutX(x1, x2, ..., xQ)

存在相互依赖关系:b1与a1相同,b2基于a2计算,它们组合成最终结果(OutX)。有些计算很昂贵。

最终结果是一个看起来类似于这个简化怪物的巨大方法:

OutX method(In in) {
  I1 i1 = in.getI1();
  I1 i2 = in.getI2();
  ...
  I1 iM = in.getIM();

  A1 a1 = fa1(i1, i2);
  A2 a2 = fa2(i2, i5, iM);
  ...
  AN aN = ...;

  OutA outA = new OutA(
    a1,
    a2,
    ...,
    aN);

  A1 b1 = a1;
  B2 b2 = fb2(a2, i5, i13);
  ...
  BO bO = ...;

  OutB outB = new OutB(
    b1,
    b2,
    ...,
    bO);   

  ...

  return new OutX(
    outA,
    outB,
    ...,
    outK);
}

'很棒的是不可改变和类型检查和东西。 '这也是300行,这是CSV的每个“风味”。啊。分解只会创建主要是参数+构造函数调用的方法。

是否有非科学怪人的模式或库?

1 个答案:

答案 0 :(得分:0)

适配器模式可能会有所帮助。每个层/ shell尽可能地委托构建最终结果。这是一个例子:

public class App {

    public static void main(String[] args) {
        App app = new App();
        app.process();
    }

    private void process() {
        In in = new In(1, 2, 3);
        OutA a = new OutA(in);
        OutB b = new OutB(a);
        System.out.println(b);
    }

    public class In {
        private final int i1;
        private final int i2;
        private final int i3;

        public In(int i1, int i2, int i3) {
            this.i1 = i1;
            this.i2 = i2;
            this.i3 = i3;
        }

        public int getI1() {
            return i1;
        }

        public int getI2() {
            return i2;
        }

        public int getI3() {
            return i3;
        }
    }

    public class OutA {
        private final In in;
        private Integer a3;

        public OutA(In in) {
            this.in = in;
        }

        public int getA1() {
            return in.getI1();
        }

        public int getA2() {
            return in.getI2() * 2;
        }

        public int getA3() {
            if (a3 == null) {
                // a3 = some expensive calculation
                a3 = 1; // hold the value to avoid expensive calculation next time method is called
            }
            return a3;
        }
    }

    public class OutB {
        private final OutA a;

        public OutB(OutA a) {
            this.a = a;
        }

        public int getB1() {
            return a.getA1();
        }

        public int getB2() {
            // a.getA3() is expensive, but only the first time it's called
            return a.getA3() + 4;
        }

        public int getB3() {
            // a.getA3() is expensive, but only the first time it's called
            return a.getA3() + 9;
        }

        public String toString() {
            return "b1: " + getB1() + " b2: " + getB2() + " b3: " + getB3();
        }
    }

}

输出:b1:1 b2:5 b3:10

更新:这是一个更有趣的例子,使用工厂进行不同的计算,但仍使用相同的界面。

public class App {

    public static void main(String[] args) {
        App app = new App();
        app.process();
    }

    private void process() {
        In in = new In(1, 2, 3);
        OutXFactory factory = new OutXFactory();

        OutX resultType1 = factory.create(in, CSVType.TYPE_1);
        System.out.println(resultType1);

        OutX resultType2 = factory.create(in, CSVType.TYPE_2);
        System.out.println(resultType2);
    }

    public class In {
        private final int i1;
        private final int i2;
        private final int i3;

        public In(int i1, int i2, int i3) {
            this.i1 = i1;
            this.i2 = i2;
            this.i3 = i3;
        }

        public int getI1() {
            return i1;
        }

        public int getI2() {
            return i2;
        }

        public int getI3() {
            return i3;
        }
    }

    public enum CSVType {
        TYPE_1, TYPE_2;
    }

    public class OutA {
        private final In in;
        private Integer a3;

        public OutA(In in) {
            this.in = in;
        }

        public int getA1() {
            return in.getI1();
        }

        public int getA2() {
            return in.getI2() * 2;
        }

        public int getA3() {
            if (a3 == null) {
                // a3 = some expensive calculation
                a3 = 1; // hold the value to avoid expensive calculation next time method is called
            }
            return a3;
        }
    }

    public class OutB {
        private final OutA a;

        public OutB(OutA a) {
            this.a = a;
        }

        public int getB1() {
            return a.getA1();
        }

        public int getB2() {
            // a.getA3() is expensive, but only the first time it's called
            return a.getA3() + 4;
        }

        public int getB3() {
            // a.getA3() is expensive, but only the first time it's called
            return a.getA3() + 9;
        }
    }

    public interface OutX {
        public int getX1();

        public int getX2();

        public int getX3();
    }

    public abstract class AbstractOutX implements OutX {

        @Override
        public String toString() {
            return "x1: " + getX1() + " x2: " + getX2() + " x3: " + getX3();
        }
    }

    public class OutXA extends AbstractOutX {
        private final OutA a;

        public OutXA(OutA a) {
            this.a = a;
        }

        @Override
        public int getX1() {
            return a.getA1() + 1;
        }

        @Override
        public int getX2() {
            return a.getA2() + a.getA3() + 2;
        }

        @Override
        public int getX3() {
            return a.getA1() + a.getA2() + 3;
        }
    }

    public class OutXAB extends AbstractOutX {
        private final OutA a;
        private final OutB b;

        public OutXAB(OutA a, OutB b) {
            this.a = a;
            this.b = b;
        }

        @Override
        public int getX1() {
            return a.getA1() + b.getB1();
        }

        @Override
        public int getX2() {
            return a.getA2() * b.getB2();
        }

        @Override
        public int getX3() {
            return (int) Math.pow(a.getA3(), b.getB3());
        }
    }

    public class OutXFactory {
        public OutX create(In in, CSVType type) {
            if (type == CSVType.TYPE_1) {
                OutA a = new OutA(in);
                return new OutXA(a);
            } else {
                OutA a = new OutA(in);
                OutB b = new OutB(a);
                return new OutXAB(a, b);
            }
        }
    }

}