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

Java 方法数组:适配器模式?,java,design-patterns,adapter,Java,Design Patterns,Adapter,问题描述: 我希望能够将方法列表传递给只在一个类中定义了方法的其他类。如果在一个类中定义了方法,其中一些方法具有输入参数和非void返回类型,我希望能够将其中一些方法的列表(可能有重复项)作为参数传递给其他类的构造函数 代码说明: 下面的代码是一个粗糙的示例,如果它偏离了主要目标,则可以忽略它。除了下面的例子之外,另一个例子是方法为int-Add(int-n1,int-n2)、int-Subtract(int-n1,int-n2)、Multiply等。。接口有一个名为int-MathOperat

问题描述: 我希望能够将方法列表传递给只在一个类中定义了方法的其他类。如果在一个类中定义了方法,其中一些方法具有输入参数和非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;
    }
}
公共类SomeClass{
...
公用两用扳手(双扭矩,布尔顺时针){…}
公用双用钳(双扭矩,布尔顺时针){…}
公用两用螺丝刀(双扭矩,布尔顺时针){…}
公共线切割机(双扭矩){…}
接口冲突{
双旋转紧固件(双扭矩,布尔顺时针);
布尔切割线(双扭矩);
}
私有iToolations[]工具操作=新iToolations[]{
新的iToolations(){公共双转紧固件(双扭矩,布尔顺时针){双用扳手(双扭矩,布尔顺时针);},
新的iToolations(){公共双转紧固件(双扭矩,布尔顺时针){双用钳子(双扭矩,布尔顺时针);},
新的iToolations(){公共双转紧固件(双扭矩,布尔顺时针){双用螺丝刀(双扭矩,布尔顺时针);},
新的iToolations(){public boolean CutWire(双扭矩){boolean usewirecutors(双扭矩);},
};
}
公社工人{

公共列表@John以下是我如何找到解决你问题的方法

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

public interface MathOperable {

    public int mathOperation(int n1, int n2);

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

下面是几个执行死刑的例子:

还有另一个例子


我希望这会有帮助!

虽然@alainlompo有一个大致的想法,但Java 8通过对类对象使用诸如
BiConsumer
(双倍)或甚至仅仅是
消费者
,大大简化了这一点。事实上,您可能会非常疯狂,并且有一个方法接受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);
        }
    }
}
虽然像这样应用它似乎有点尴尬(因为它是一种适配器模式),但您可以很容易地看到它是如何应用于类主体的:

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);
java 8中的函数API提供了更大的灵活性,使类似这样的复杂问题的编写变得极其简单。

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

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

但首先,更一般地说,设计“可重用软件的元素”(源于原始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); ... }
}
希望您能够清楚地了解如何将其扩展到您的示例中。工作人员将成为直接向前的工具列表(或者,为了清楚起见,将其称为“命令”,而不是“工具”)

公共类工作者{
公开名单行动清单;
....
公共工程(){
对于(…){
action.execute();
}
}
}

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

我想我知道你在追求什么,但我需要一个更好的问题描述或更好的例子。停顿似乎是方法参数和返回值。你必须定义一些方法来处理这些问题,你的特定需求将决定需要如何工作。没有通用的“X”总是解决这类问题。也许可以解释一下你遇到了什么问题
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);
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!
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();
      }
    }
}