For investors
股价:
5.36 美元 %For investors
股价:
5.36 美元 %认真做教育 专心促就业
Mapper接口和MapperComponent
如果仅仅使用ConstructorComponent、StaticFactoryComponent、InstanceFactoryComponent,是无法实现这个需求的,因为这几个Component最多只能表示如何将对象创建出来,但是在对象创建出来之后,我们还希望对这个对象进行更多的设置,比如调用setter方法设置属性,或者调用初始化方法等等。
首先,我们需要一个东西来封装对一个对象的操作:
public interface Mapper
{
Object map(Object obj);
}
Mapper接口是一个十分通用的接口,表示转换操作,它的map方法接受某个对象,然后返回经过处理后的对象。
接下来实现一个MapperComponent:
public class MapperComponent implements Component
{
private final Component component;
private final Mapper mapper;
public MapperComponent(Component component, Mapper mapper)
{
this.component = component;
this.mapper = mapper;
}
@Override
public Object create()
{
return mapper.map(component.create());
}
}
MapperComponent创建时需要传入一个Component和Mapper。MapperComponent可以在上一个Component的基础上,通过调用Mapper的map方法,对上一个Component生成的对象进行进一步处理。
然后可以在Component中实现几个默认方法:
public interface Component
{
...
default Component map(Mapper mapper)
{
return new MapperComponent(this, mapper);
}
default Component setProperty(String property, Component value)
{
return this.map(obj ->
{
// 获取属性值
Object v = value.create();
// 调用JavaBean的API将obj的property属性设置为v
...
});
}
default Component invokeSetter(String setter, Component... params)
{
return this.map(obj ->
{
// 获取参数值
Object[] p = Arrays.stream(params).map(Component::create).toArray();
// 反射调用obj的setter方法,并传递参数
...
});
}
}
把这些常用操作封装成Component接口的默认方法后,所有的Component都能以链式调用的形式来组合这些操作,详见下面的使用示例。
setProperty用于声明对象属性的设置,property是属性名,value是用于生成属性值的组件。注意,这里value的类型是Component而不是Object,因为属性值可能是一个组件。
invokeSetter用于声明调用对象的setter方法,setter是setter方法名,params是传递的参数,setter方法的参数同样也可以是组件,所以params的类型为Component[]。
实际上,设置属性也是通过调用相应的setter方法实现的,setProperty与invokeSetter的区别在于,某些setter方法可以同时设置两个属性,如obj.setNameAndAge("XiaoMing", 17);另外,invokeSetter也可以用来调用某些初始化方法,如obj.init(...)。
使用ByxContainer
到这里,对象初始化的需求就完成得差不多了,本篇文章实现的对象初始化方式结合上一篇文章实现的对象创建一起使用,可以表达十分多样的需求。下面给出一些使用示例,以加深理解:
/*
Student s = new Student();
s.setId(1001);
s.setName("XiaoMing");
s.setAge(17);
s.setScore(87.5);
*/
Component s = constructor(Student.class)
.setProperty("name", value("XiaoMing"))
.setProperty("age", value(17))
.setProperty("score", value(87.5));
/*
Student s = new Student();
s.setNameandAge("XiaoMing", 17);
s.setScore(87.5);
*/
Component s = constructor(Student.class)
.invokeSetter("setNameAndAge", value("XiaoMing"), value(17))
.invokeSetter("setScore", value(87.5));
/*
StringBuilder builder = new StringBuilder();
builder.append("hello");
builder.append(" world");
String str = builder.toString();
*/
Component builder = constructor(StringBuilder.class)
.invokeSetter("append", value("hello"))
.invokeSetter("append", value(" world"));
Component str = instanceFactory(builder, "toString");