首页 > 解决方案 > 使用参数和源块创建代理

问题描述

我用几个参数创建了自己的流程图块。其中两个属于“代理”类型,在 Main 中我选择了相应的代理。我的块所做的是,它根据进入块的代理创建新代理(有点像批处理块)。

到目前为止,我能够验证传入代理以确保在 Main 中选择了正确的代理类型。现在我想用一个源块和注入函数创建另一个代理。但是我的问题来了。我想根据所选参数(类型代理)动态创建代理。显然,仅将参数的名称放在新的代理字段中是行不通的(它确实有效,但仅适用于第一个代理 - 之后我收到一个错误,因为创建了同一个代理)。我知道通常我必须使用“ new Agent() ”之类的东西来创建新的代理,但我找不到参数值和代理类型之间的链接。

我的问题是,我尝试使我的块尽可能可定制,这意味着我想在未来的项目中再次使用这个块,而不需要更改代码(或至少更改太多)。每个项目都会有不同的代理、变量、名称、参数等。

编辑:添加截图

我的块的简化版本

标签: parametersanylogicagent

解决方案


有两种方法可以实现这一点:通过 Java 反射和使用 java.util.function.Supplier。请注意,这两种方法的缺点是,由于事先不知道生成的代理的类型,因此代码将新实体称为代理,但它实际上创建了正确类型的代理,可以使用“instanceof”进行检查或投。

下面提供了这两个版本。在接下来的 2 小时内,可以在此处找到示例 .alp。在此示例中,有 2 个代理MainProgrammaticAgent

主要代理视图

ProgrammaticAgent 视图

现在谈谈创作的方法。

  1. 通过 Java 反射

这是两者中最不可取的方法。在示例代理中,代码位于“直接创建”按钮的操作属性中。代码如下,更详细的描述请阅读评论。

// This is the name of the class that needs to be created
//  as a string. It can be passed as a parameter. 
// NOTE: you need the whole name including package name 
//  (in this case 'testprogcreation.' but you'll have your own) 
String classNameValue = "testprogcreation.ProgrammaticAgent";

try {
    // get a handle on the Class of that agent
    Class agentClass = Class.forName(classNameValue);
    
    // find the Constructor
    Constructor c = agentClass.getDeclaredConstructor(
        com.anylogic.engine.Engine.class,
        com.anylogic.engine.Agent.class,
        com.anylogic.engine.AgentList.class);
        
    // Create the agent. Now, because we don't know the type
    // at compile time it has to be declared as 'Agent' here
    // but in actuality it is of type specified in 'classNameValue' above
    Agent agent = 
        (Agent)c.newInstance(getEngine(), this, getDefaultPopulation());
    
    // add to default population
    ((AgentLinkedHashSet<Agent>)getDefaultPopulation())._add(agent);
        
    // set up parameters by name
    agent.setParameter("parameterOne", 5.0, false);
    agent.setParameter("parameterTwo", "some value", false);
    agent.markParametersAreSet(); // <- mark that parameters are set

    // tell AnyLogic that agent is created and started  
    agent.create();
    agent.start();
    
    // now you can do whatever with the agent, in this case send it
    // via 'enter' into some process
    enter.take(agent);
} catch (Exception e) {
    e.printStackTrace();
    error("Could not instantiate %s, see Console for full error", classNameValue);
}
  1. 通过功能供应商

这是一个更整洁的方法。这里将创建新代理的块有一个名为agentSupplier的动态参数(见图),类型为java.util.function.SupplieragentSupplier.get()在需要代理的新实例时调用。

然后向该供应商提供对“add_”方法的引用,该方法由 AnyLogic 在创建代理群体对象时自动生成。在这种情况下,总体称为“programmaticAgents”,因此该方法称为“add_programmaticAgents(...”)。

agentCreator 参数

请注意,在上图中,默认值字段中的代码实际上会在封闭代理中更改,以反映正确的自动创建方法。


推荐阅读