使用参数和源块创建代理
Create agents with a parameter and a sourceblock
我用一些参数创建了自己的流程图块。其中两个是 'Agent' 类型,在 Main 中我选择了相应的代理。我的块所做的是,它根据进入块的代理创建新代理(有点像批处理块)。
到目前为止,我能够验证传入代理以确保在 Main 中选择了正确的代理类型。现在我想创建另一个具有源代码块和注入功能的代理。但是我的问题来了。我想根据所选参数(类型代理)动态创建代理。显然,仅将参数名称放在新代理字段中是行不通的(它确实有效,但仅适用于第一个代理 - 之后我收到错误,因为创建了同一个代理)。我知道通常我必须使用类似 'new Agent()' 的东西来创建新代理,但我找不到参数值和代理类型。
我的问题是,我试图让我的块尽可能可定制,这意味着我想在未来的项目中再次使用这个块而根本不改变代码(或至少改变太多)。每个项目都会有不同的代理、变量、名称、参数等
编辑:添加了截图
Simplified version of my block
我不确定这是否有帮助,但我认为这是可以引导您找到正确答案的方法...我也不确定我是否真的理解您想要什么
首先,可以将源创建为群体,群体中的每个成员都创建不同的代理类型...像这样:
在这个例子中,我有一个包含 2 个源的数组...现在,您想要从数组中的每个源生成不同的代理类型...为此您需要在新的源上创建一个函数returns 一个 Agent
的 agent 参数
此函数将源群体的来源索引作为参数...这是一个局部变量,您可以在创建对象群体时自由使用
现在函数看起来像这样:
Agent x=null;
if(index==0)
x=new MyAgent1();
else if(index==1)
x=new MyAgent2();
return x;
现在唯一的问题是你每次在新模型上有新条件时都必须重写这个函数,但是根据你有多少代理类型,它可能不会那么多工作....
选择可以通过索引完成...所以如果您有类似的东西,您可以使其足够灵活...如果这是正确的方向,也许我们可以在您提供更多信息时进行改进
您当然可以使用 source.get(index).inject();
注入代理
并且您使用的参数是索引,而不是代理类型。您可以使用
制作地图
index -> agent type
模型中的其他地方
首先感谢大家的指点。
我在原来的 post 的基础上添加了一个小截图。如前所述,我的块背后的想法是我想根据传入的代理和参数生成新元素。例如,如果我将关联参数设置为代理“B”,我想将代理“A”转换为代理“B”。
我这里的问题不是实现。我可以对一切正常工作的东西进行硬编码。我的想法是创建我自己的自定义库,我可以重复使用或与其他同事共享。所以每个自定义块都应该尽可能的可定制和万无一失。
最后我做了类似 Felipe 建议的事情 - 编写了一个使用 instanceof
的函数。
Agent a = null;
if(pToAgent instanceof Lot){
a = new Lot();
}else if(pToAgent instanceof Magazine){
a = new Magazine();
}else if(pToAgent instanceof Module){
a = new Module();
}else{
traceln("CustomUnbatch: Error - Undefined Agent-type");
}
return a;
此解决方案的唯一缺点是,当添加新代理或启动新项目时,必须一次又一次地更改功能。也许将来我会包含映射 table 的想法,这样我就不必向函数添加更多行。
有两种方法可以实现:通过Java反射和使用java.util.function.Supplier。请注意,这两种方法的缺点是,由于事先不知道生成的代理的类型,因此代码将新实体引用为 Agent 但它实际上创建了正确的代理类型,可以使用 'instanceof' 或 cast.
检查
下面提供了两个版本。在接下来的 2 小时内可以找到示例 .alp here。在此示例中,有 2 个代理 Main 和 ProgrammaticAgent.
现在介绍创作方法。
- 通过Java反射
这是两种方法中最不推荐的方法。在示例 Main 代理中,代码在 action 属性 的 'create directly' 按钮中。代码如下,更详细的说明请阅读评论
// 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);
}
- 通过功能供应商
这是一种更简洁的方法。这里将创建新代理的块有一个名为 agentSupplier 的动态参数(见图),类型为 java.util.function.Supplier 并调用 agentSupplier.get()
当需要代理的新实例时。
此 供应商 然后提供对 'add_' 方法的引用,该方法在创建代理人口对象时由 AnyLogic 自动生成。在这种情况下,总体称为 'programmaticAgents',因此该方法称为 'add_programmaticAgents(...'.
请注意,在上图中,默认值 字段中的代码实际上会在封闭代理中更改,以反映正确的自动创建方法。
我用一些参数创建了自己的流程图块。其中两个是 'Agent' 类型,在 Main 中我选择了相应的代理。我的块所做的是,它根据进入块的代理创建新代理(有点像批处理块)。
到目前为止,我能够验证传入代理以确保在 Main 中选择了正确的代理类型。现在我想创建另一个具有源代码块和注入功能的代理。但是我的问题来了。我想根据所选参数(类型代理)动态创建代理。显然,仅将参数名称放在新代理字段中是行不通的(它确实有效,但仅适用于第一个代理 - 之后我收到错误,因为创建了同一个代理)。我知道通常我必须使用类似 'new Agent()' 的东西来创建新代理,但我找不到参数值和代理类型。
我的问题是,我试图让我的块尽可能可定制,这意味着我想在未来的项目中再次使用这个块而根本不改变代码(或至少改变太多)。每个项目都会有不同的代理、变量、名称、参数等
编辑:添加了截图
Simplified version of my block
我不确定这是否有帮助,但我认为这是可以引导您找到正确答案的方法...我也不确定我是否真的理解您想要什么
首先,可以将源创建为群体,群体中的每个成员都创建不同的代理类型...像这样:
在这个例子中,我有一个包含 2 个源的数组...现在,您想要从数组中的每个源生成不同的代理类型...为此您需要在新的源上创建一个函数returns 一个 Agent
的 agent 参数此函数将源群体的来源索引作为参数...这是一个局部变量,您可以在创建对象群体时自由使用
现在函数看起来像这样:
Agent x=null;
if(index==0)
x=new MyAgent1();
else if(index==1)
x=new MyAgent2();
return x;
现在唯一的问题是你每次在新模型上有新条件时都必须重写这个函数,但是根据你有多少代理类型,它可能不会那么多工作....
选择可以通过索引完成...所以如果您有类似的东西,您可以使其足够灵活...如果这是正确的方向,也许我们可以在您提供更多信息时进行改进
您当然可以使用 source.get(index).inject();
并且您使用的参数是索引,而不是代理类型。您可以使用
制作地图index -> agent type
模型中的其他地方
首先感谢大家的指点。
我在原来的 post 的基础上添加了一个小截图。如前所述,我的块背后的想法是我想根据传入的代理和参数生成新元素。例如,如果我将关联参数设置为代理“B”,我想将代理“A”转换为代理“B”。
我这里的问题不是实现。我可以对一切正常工作的东西进行硬编码。我的想法是创建我自己的自定义库,我可以重复使用或与其他同事共享。所以每个自定义块都应该尽可能的可定制和万无一失。
最后我做了类似 Felipe 建议的事情 - 编写了一个使用 instanceof
的函数。
Agent a = null;
if(pToAgent instanceof Lot){
a = new Lot();
}else if(pToAgent instanceof Magazine){
a = new Magazine();
}else if(pToAgent instanceof Module){
a = new Module();
}else{
traceln("CustomUnbatch: Error - Undefined Agent-type");
}
return a;
此解决方案的唯一缺点是,当添加新代理或启动新项目时,必须一次又一次地更改功能。也许将来我会包含映射 table 的想法,这样我就不必向函数添加更多行。
有两种方法可以实现:通过Java反射和使用java.util.function.Supplier。请注意,这两种方法的缺点是,由于事先不知道生成的代理的类型,因此代码将新实体引用为 Agent 但它实际上创建了正确的代理类型,可以使用 'instanceof' 或 cast.
检查下面提供了两个版本。在接下来的 2 小时内可以找到示例 .alp here。在此示例中,有 2 个代理 Main 和 ProgrammaticAgent.
现在介绍创作方法。
- 通过Java反射
这是两种方法中最不推荐的方法。在示例 Main 代理中,代码在 action 属性 的 'create directly' 按钮中。代码如下,更详细的说明请阅读评论
// 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);
}
- 通过功能供应商
这是一种更简洁的方法。这里将创建新代理的块有一个名为 agentSupplier 的动态参数(见图),类型为 java.util.function.Supplier 并调用 agentSupplier.get()
当需要代理的新实例时。
此 供应商 然后提供对 'add_' 方法的引用,该方法在创建代理人口对象时由 AnyLogic 自动生成。在这种情况下,总体称为 'programmaticAgents',因此该方法称为 'add_programmaticAgents(...'.
请注意,在上图中,默认值 字段中的代码实际上会在封闭代理中更改,以反映正确的自动创建方法。