不同类实例和对象共享的链接方法



对于下面的示例代码...

  1. 有没有办法chain instances of different classes?提供的示例是连接属于不同类实例的方法的失败尝试。

  2. 此外,在同一示例中,Client2Client3共享错误对象。什么是更有效的sharing objects between subclasses and unassociated classes方式?

为了清楚起见,我还进行了内联评论。

感谢您的时间和帮助。

示例代码

public class StubRunner
{
public run(){
ClientFactory client = new ClientFactory();
//not correct. But, this is how i want to finally chain methods 
//belonging to different class instances. Please advise.
client.getClient1().testClient1().getClient2().testClient2().assert(...);
}
}
public class ClientFactory
{
public Client1 getClient1(){return new Client1();}
public Client2 getClient2(){return new Client2();}
}
public class BaseClient
{
public Errors errors = null; 
}
public class Client1 extends BaseClient
{
public void testClient1(){...}
}
public class Client2 extends BaseClient
{
public void testClient2()
{
//here i am directly passing the error object
//what is a better way?
//is there a more efficient way to make the SAME error object
//available to Client3
new Client3(this.errors).testClient3();
...
}
}
public class Client3 extends BaseClient
{
public Client3(Errors errors){this.errors = errors;}
public void testClient3(){...}
}

当我想编写短方法调用链但我希望方法相对于任何类型的状态进行更改时,我通常会使用 lambda 表达式。至于您的场景,您的每个测试都将是一个 lambda 表达式,这意味着我将 testClient4 方法传递给 testClient3 方法,将 testClient3 方法传递给 testClient2 方法,依此类推。但是,随着方法调用链变长,代码变得越来越丑陋。

=> 您可以使用 Fluent 接口:您将让每个方法执行一些逻辑,然后返回一个实例,您可以在该实例上调用要执行的下一个内联方法。

  • ClientFactory.getClient1() : Client1
  • Client1.testClient1() : Client1 (即返回这个)
  • Client1.getClient2() : Client2
  • Client2.testClient2() Client2 (即返回 this)

显然,每个实例都需要引用下一个内联实例,知道它将调用哪个实例(Client1 将引用 Client2,Client2 引用 Client3,依此类推)。

这将起作用,但我不是这种情况的粉丝!我会说这更像是一个技巧,而不是干净的编码。您应该单独对每个客户端使用 fluent 接口,除非您的其中一个方法实际上返回了另一个实例:

client1.testClient1().testClient2().testClient3() 每个测试方法返回下一个客户端的实例(如果有充分的理由)

但是在测试方法之间插入getClient方法是没有意义的...

我并没有真正了解您的真正需求,但是在代码的实际状态下,它甚至无法编译,因为您正在尝试从 void 方法返回的"Client"对象执行方法。

如果您不知道将获得多少客户端以及从哪种类型获得,我只会使用列表。

如果你想使用'testClient'方法链接客户端,那么首先这个方法应该返回下一个客户端(顺便说一下,这是一种非常尴尬的链对象的方式),然后你应该开始使用更多的抽象和覆盖技术。

基本上,只要它是"BaseClient",就不需要知道你正在处理什么对象,但是如果你将子方法命名为"testClient1"、"testClient2"等......你基本上打破了它,你需要开始考虑你实际得到的东西并相应地调整你的代码。

最后,这里不需要工厂,但如果你想要一个,它应该是静态的。

这是一个工作示例,同样,我并不真正理解您想要做什么,因此它可能无法解决您的问题,但它是"链接实例"的有效解决方案:

主要:

public class Foo
{
// arguments are passed using the text field below this editor
public static void main(String[] args)
{
StubRunner stub = new StubRunner();
stub.run();
}
}

顽固者:

public class StubRunner implements Runnable
{
public void run(){
Object clients = ClientFactory.getClient1();
while (null!= clients && clients instanceof BaseClient) {
clients = ((BaseClient) clients).test();            
}
}
}

基础:

public abstract class BaseClient
{
public Exception errors = null; 

public BaseClient() {};
public BaseClient(Exception errors) {
this.errors = errors;
}
public abstract BaseClient test();
public void checkErrors() {
System.out.println(this.toString());
assert null == errors;
}
}

客户端 1:

public class Client1 extends BaseClient
{
public BaseClient test(){
checkErrors();
return new Client2();      
}
}

客户端 2:

public class Client2 extends BaseClient
{
public BaseClient test()
{
checkErrors();
return new Client3(this.errors);
}
}

客户端 3:

public class Client3 extends BaseClient
{
public Client3(Exception errors) {
super(errors);
}
public BaseClient test() {
checkErrors();
return null;
}
}

厂:

公共最终类 客户端工厂 { private ClientFactory() {};

public static Client1 getClient1(){return new Client1();}
public static Client2 getClient2(){return new Client2();}

}

这将输出以下内容:

测试。Client1@15db9742 测试。Client2@6d06d69c 测试。Client3@7852e922

有没有办法链接不同类的实例?提供的示例是连接属于不同类实例的方法的失败尝试。

client.getClient1().testClient1().getClient2().testClient2().assert(...);

为了像这样链接方法,每个方法必须返回对支持要调用的方法的对象的引用。但是,每个测试方法都返回void

在这种情况下,方法链接似乎非常值得怀疑,因为您正在操作不同的类型。通常,像这样的链中的方法只会return this;,以便可以在启动链的完全相同的对象上调用另一个方法。

此外,方法的名称表明您正在尝试实现代码的一些自动测试。您应该了解已建立的测试技术和库。特别是,JUnit通常用于Java和其他语言的变体。在这样的框架中编写测试时,某些技术被认为是良好的做法。

为了明确这一点,您当然不应该将测试代码与生产代码混合在一起。

此外,在同一示例中,客户端 2 与客户端 3 共享错误对象。在子类和未关联的类之间共享对象的更有效方法是什么?

//here i am directly passing the error object
//what is a better way?
//is there a more efficient way to make the SAME error object
//available to Client3
new Client3(this.errors).testClient3();

将对象发送到类的唯一方法是将参数传递给构造函数或方法。这就是Java的工作方式。

请注意,开销很小,因为您正在传递引用变量。您不会复制整个对象。这意味着Client2的当前实例和Client3的新实例都具有对同一错误对象的引用。

现在testClient1()可以返回客户端工厂等。但这是非常复杂的。

另一种监管语法是覆盖提供类的上下文。

new ClientFactory() {{
getClient1().testClient1();
getClient2().testClient2().assert(...);
}};

在这里,初始化块("匿名构造函数")将提供一个上下文。 然后,当 testClient2 返回 Client2 时,可以进行一些链接。

它可以是一个干净而有用的设计,例如对于我的模棱两可的语法解析器AnyParser sourceforge.net(纯粹是一项工艺工作)。

谢谢大家的大力帮助。您的建议使我能够得出以下工作解决方案。也许这不是最好的,所以寻求您的宝贵时间和专业知识来指导更好的解决方案。

鉴于我的命名惯例有些评论是可疑的,我试图在一定程度上修改它们。请耐心等待。

目标是:

  • chain instances of different classes
  • share objects between subclasses and unassociated classes

问题描述:

有 4 个任务要
  • 执行:任务 1 到任务 4。
  • 每个任务都是独一无二的。但有时,要完成一项任务,我们需要执行混合任务:参考任务3>>执行混合任务()
  • 要完成一项工作,我们需要完成一组任务。

状态.java

public class State {
public Boolean ISAUDITED = false;
public int ERRORCODE = 0;
public String ERRORTEXT = "";
public void raise(int code, String msg){
this.ERRORCODE = code;
this.ERRORTEXT = msg;
}
}

基本客户端.java

public abstract class BaseClient {
public State state;
public BaseClient(){
this.state = new State();
}
public BaseClient(State state){
this.state = state;
}
public ClientFactory getTest(){
return new ClientFactory(state);
}
public Boolean Assert(){
if(state.ERRORCODE == 0){
System.out.println("Parsing was successful.");
return true;
}
else{
System.out.println("Parsing was not successful.");
return false;
}
}
public abstract BaseClient GoTo();
}

任务 1.java

public class Task1 extends BaseClient {
public Task1(){ GoTo(); }
public Task1(State state){ super(state); GoTo(); }  
public Task1 performTask1(){
if(!state.ISAUDITED)
{
System.out.println("perform Task1");
state.ISAUDITED = true;
}
return this;
}
@Override
public BaseClient GoTo() {
if(state.ISAUDITED){
new Task2(state).performTask2();
}
return this;
}
}

任务2.java

public class Task2 extends BaseClient{
public Task2(){ GoTo(); }
public Task2(State state){ super(state); GoTo(); }      
public Task2 performTask2(){
if(state.ISAUDITED)
{
System.out.println("perform Task2");
state.ISAUDITED = false;
}
return this;
}
@Override
public BaseClient GoTo() {
if(!state.ISAUDITED){
new Task1().performTask1();
}
return this;
}
}

任务3.java

public class Task3 extends BaseClient {
public Task3(){ }
public Task3(State state){ super(state); }
public Task3 GoTo(){
if(!state.ISAUDITED) {new Task1(state).performTask1();}
System.out.println("Opening Task3");
return this;
}
public Task3 performTask3(){
try
{
this.GoTo();
System.out.println("Submitted Task3 Data");
}
catch(Exception e){
state.raise(1, e.getMessage());
}
return this;
}
public Task3 performMixedTasks(){
new Task4(state).performTask4();        
this.performTask3();        
return this;
}
}

任务4.java

public class Task4 extends BaseClient {
public Task4(){ }
public Task4(State state){ super(state); }
public Task4 GoTo(){
if(!state.ISAUDITED) {new Task1(state).performTask1();}
System.out.println("Opening Task 4");
return this;
}
public Task4 performTask4(){
try
{
this.GoTo();
System.out.println("Submitted Task 4 Data");
}
catch(Exception e){
state.raise(1, e.getMessage());
}
return this;
}
}

客户端工厂.java

public class ClientFactory {
State state;
public ClientFactory(){
state = new State();
}
public ClientFactory(State state){
this.state = state;
}
public Task3 loadTask3(){return new Task3(state);}
public Task4 loadTask4(){return new Task4(state);}
}

存根跑者1.java

public class StubRunner1 {
public static void main(String[] arg)
{
ClientFactory test = new ClientFactory();
test.loadTask3()
.performTask3()
.getTest()
.loadTask4()
.performTask4()
.Assert();
}
}
**RESULT IS**
perform Task1
Opening Task3
Submitted Task3 Data
Opening Task4
Submitted Task4 Data
Parsing was successful.

存根跑者2.java

public class StubRunner2 {
public static void main(String[] args) {
ClientFactory test = new ClientFactory();
test.loadTask3()
.performMixedTasks()
.Assert();
}
}
**RESULT IS**
perform Task1
Opening Task4
Submitted Task4 Data
Opening Task3
Submitted Task3 Data
Parsing was successful.

最新更新