有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java方法数组:适配器模式?

问题描述: 我希望能够将方法列表传递给只在一个类中定义了方法的其他类。如果在一个类中定义了方法,其中一些方法具有输入参数和非void返回类型,我希望能够将其中一些方法的列表(可能有重复项)作为参数传递给其他类的构造函数

代码说明: 下面的代码是一个粗糙的示例,如果它偏离了主要目标,则可以忽略它。除了下面的例子之外,另一个例子是方法为int-Add(int-n1,int-n2)、int-Subtract(int-n1,int-n2)、Multiply等。。接口有一个名为int-MathOperation的方法(int-n1,int-n2)

尝试解决问题: 适配器模式似乎具有我正在寻找的功能,但我只看到接口中的方法没有输入或输出参数的示例。下面是我为这个问题编写的一个示例实现

问题类比: 您有一个随机图片生成器web服务。有30种突变可以应用于图像。客户端连接并单击“生成”按钮,其中一些函数的随机列表被传递给web服务中的其他类,然后这些类继续使用自己的数据运行这些函数,同时还收集并可能重新使用返回值来生成一些变异的cat映像。它不能只显式调用另一个类中的方法,因为该过程需要在运行时随机完成。这就是为什么我倾向于生成一个随机的方法列表,这些方法在单击“生成”按钮时按顺序执行

我希望我已经说清楚了

public class SomeClass {
    ...
    public double UseWrench(double torque, boolean clockwise) { ... }
    public double UsePliers(double torque, boolean clockwise) { ... }
    public double UseScrewDriver(double torque, boolean clockwise) { ... }
    public boolean UseWireCutters(double torque) { ... }

    interface IToolActions {
        double TurnFastener(double torque, boolean clockwise);
        boolean CutWire(double torque);
    }

    private IToolActions[] toolActions = new IToolActions[] {
        new IToolActions() { public double TurnFastener(double torque, boolean clockwise) { double UseWrench(double torque, boolean clockwise); } },
        new IToolActions() { public double TurnFastener(double torque, boolean clockwise) { double UsePliers(double torque, boolean clockwise); } },
        new IToolActions() { public double TurnFastener(double torque, boolean clockwise) { double UseScrewDriver(double torque, boolean clockwise); } },
        new IToolActions() { public boolean CutWire(double torque) { boolean UseWireCutters(double torque); } },
    };
}

public class Worker<T> {

    public List<? extends IToolActions> toolActions;

    public Worker(List<? extends IToolActions> initialToolSet){
        toolActions = initialToolActions;
    }
}

共 (3) 个答案

  1. # 1 楼答案

    好吧,我要成为“那个家伙”。。。一个理解问题但无论如何都要求重述问题的人,因为我认为你走错了路。所以,请容忍我:如果你喜欢你所看到的,那就太好了;如果不是,我理解

    基本上,你的意图/动机/目的与“适配器”的用途不同。命令模式更适合

    但首先,更一般地说,设计“可重用软件的元素”(源于原始GOF设计模式书的标题)的目标之一是,当您添加功能时,您不想修改代码;相反,您希望在不触及现有功能的情况下添加代码。所以,当你有:

    public class Toolbox {
        public void hammer() { ... }
    }
    

    如果你想在工具箱里加一把螺丝刀,这很糟糕:

    public class Toolbox {
        public void hammer() { ... }
        public void screwdriver() { ... }
    }
    

    相反,在理想情况下,所有现有代码都将保持不变,您只需添加一个新的编译单元(即,添加一个新文件)和一个单元测试,然后对现有代码进行回归测试(这不太可能,因为现有代码都没有更改)。例如:

    public class Toolbox {
        public void useTool(Tool t) { t.execute(); ...etc... }
    }
    
    public interface Tool { // this is the Command interface
         public void execute() // no args (see ctors)
    }
    
    public Hammer implements Tool {
         public Hammer(Nail nail, Thing t) // args!
         public void execute() { nail.into(t); ... }
    }
    
    public Screwdriver implements Tool {
         public Screwdriver(Screw s, Thing t)
         public void execute() { screw.into(t); ... }
    }
    

    希望它能清楚地说明如何将其扩展到您的示例中。工作人员直接进入工具列表(或者,为了清楚起见,不用“工具”,只需称之为“命令”)

    public class Worker {
        public List<Command> actionList;
         ....
        public void work() {
          for(...) {
             action.execute();
          }
        }
    }
    

    这种模式还允许轻松的“撤销”功能和“重试”,以及记忆(缓存结果,以便不必重新运行)

  2. # 2 楼答案

    虽然@alainlompo有一般的想法,但Java8通过使用诸如BiConsumer(对于double)或甚至仅仅是类对象的Consumer之类的东西大大简化了这一点。事实上,你可以疯狂地接受varargs lambdas:

    public class SomeClass
    
        public double useWrench(double torque, boolean clockwise) { ... }
        public double usePliers(double torque, boolean clockwise) { ... }
        public double useScrewDriver(double torque, boolean clockwise) { ... }
        public boolean useWireCutters(double torque) { ... }
    
    }
    
    public class Worker {
    
        @SafeVarargs
        public Worker(SomeClass example, Consumer<? extends SomeClass>... operations) {
            for (Consumer bc : operations) {
                bc.accept(example);
            }
        }
    }
    

    然后,这很容易简化:

    SomeClass c = new SomeClass();
    new Worker(c, SomeClass::useWrench, SomeClass:usePliers, SomeClass::useScrewDriver, SomeClass::useWireCutters);
    

    虽然这样应用它似乎有点尴尬(因为它是一种适配器模式),但您可以很容易地看到它如何应用于类主体:

    public class SomeClass
    
        public double useWrench(double torque, boolean clockwise) { ... }
        public double usePliers(double torque, boolean clockwise) { ... }
        public double useScrewDriver(double torque, boolean clockwise) { ... }
        public boolean useWireCutters(double torque) { ... }
    
        @SafeVarargs
        public void operate(Consumer<? extends SomeClass>... operations) {
            for (Consumer<? extends SomeClass> bc : operations) {
                bc.accept(example);
            }
        }
    
    }
    
    //Elsewheres
    SomeClass c = new SomeClass();
    c.operate(SomeClass::useWrench, SomeClass:usePliers, SomeClass::useScrewDriver, SomeClass::useWireCutters);
    

    当然,您不需要varargs,只需传递一个Collection就可以了

    等等,还有更多

    如果你想要一个结果,你甚至可以通过Function使用一个自返回方法,例如:

    public class SomeClass {
    
        public double chanceOfSuccess(Function<? super SomeClass, ? extends Double> modifier) {
            double back = /* some pre-determined result */;
            return modifier.apply(back); //apply our external modifier
        }
    
    }
    
    //With our old 'c'
    double odds = c.chanceOfSuccess(d -> d * 2); //twice as likely!
    

    java 8中的函数API提供了更大的灵活性,使类似这样的复杂问题的编写变得极其简单

  3. # 3 楼答案

    @John这是我解决你问题的方法

    我使用了MathOperations的例子来简化它。首先,我认为我最好将接口放在某个类之外,比如:

    public interface MathOperable {
    
        public int mathOperation(int n1, int n2);
    
    }
    

    我创建了两个实现这个接口的类的示例,以及SomeClass内部的一个匿名实现(我做了一个加法、乘法和一个匿名“减法”)

    public class Add implements MathOperable {
    
        public int mathOperation(int n1, int n2) {
    
            return n1 + n2;
        }
    
        public String toString() {
            return "<addition>";
        }
    
    }
    

    重写toString()只是为了让我将在本文末尾展示的示例更具可读性

    public class Multiply implements MathOperable {
    
        public int mathOperation(int n1, int n2) {
            // TODO Auto-generated method stub
            return n1 * n2;
        }
    
        public String toString() {
            return "<multiplication>";
        }
    
    }
    

    这是我的SomeClass类,它包含一个GetRandomListoOperations,在这里我模拟当点击按钮时发生的事情

    public class SomeClass {
    
        private static MathOperable addition = new Add();
        private static MathOperable multiplication = new Multiply();
    
        // Anonymous substraction  
        private static MathOperable substraction = new MathOperable() {
    
            public int mathOperation(int n1, int n2) {
                // TODO Auto-generated method stub
                return n1-n2;
            }
    
            public String toString() {
                return "<substraction>";
            }
    
        };
    
    
        public List<MathOperable> getRandomListOfOperations() {
    
            // We put the methods in an array so that we can pick them up later     randomly
            MathOperable[] methods = new MathOperable[] {addition,     multiplication, substraction};
            Random r = new Random();
    
            // Since duplication is possible whe randomly generate the number of     methods to send
            // among three so if numberOfMethods > 3 we are sure there will be     duplicates
            int numberOfMethods = r.nextInt(10);
            List<MathOperable> methodsList = new ArrayList<MathOperable>();
    
            // We pick randomly the methods with duplicates
            for (int i = 0; i < numberOfMethods; i++) {
                methodsList.add(methods[r.nextInt(3)]);
    
            }
    
            return methodsList;     
        }
    
        public void contactSomeOtherClass() {
            new SomeOtherClass(getRandomListOfOperations());
        }
    }
    

    这是我的SomeOther类(可能对应于你的工人类)

    public class SomeOtherClass<T extends MathOperable> {
    
        Random r = new Random();
    
        List<T> operations;
    
        public SomeOtherClass(List<T> operations) {
            this.operations = operations;
    
            runIt();
        }
    
        public void runIt() {
    
            if (null == operations) {
                return;
            }
    
            // Let's imagine for example that the new result is taken as     operand1 for the next operation
            int result = 0;
    
            // Here are examples of the web service own datas
            int n10 = r.nextInt(100);
            int n20 = r.nextInt(100);
    
            for (int i = 0; i < operations.size(); i++) {
    
                if (i == 0) {
                    result = operations.get(i).mathOperation(n10, n20);
                    System.out.println("Result for operation N "  + i + " = " +     result);
                } else {
    
                    // Now let's imagine another data from the web service     operated with the previous result
                    int n2 = r.nextInt(100);
                    result = operations.get(i).mathOperation(result, n2);
                    System.out.println("Current result for operation N " + i + "     which is " + operations.get(i) +" = " + result);
    
                }
            }
        }
    

    }

    我有一个简单的测试类,它包含一个连接这两个类的main

    public class SomeTestClass {
    
        public static void main(String[] args) {
            SomeClass classe = new SomeClass();
            classe.contactSomeOtherClass();
        }
    
    }
    

    下面是几个处决的例子:

    example1

    还有另一个例子

    example 2

    我希望这能有所帮助