本系列文章介紹ByxContainer的實作思路,
ByxContainer是一個簡單的輕量級IOC容器,具有以下特性:
- 使用JSON格式的組態檔
- 支持建構式注入、靜態工廠注入、實體工廠注入、屬性注入、setter注入、條件注入
- 組件的延遲加載和單例組件
- 根據id注冊、獲取容器中的組件
ByxContainer的設計借鑒了ajoo大神的博客,
專案地址:github 碼云
本篇文章介紹ByxContainer中與物件初始化有關的設計,
回顧
在上一篇文章中,我們解決了物件創建的問題,但是在實際開發中,我們把一個物件創建出來后,還需要做一些其它的事情來完成物件的初始化:
Student s = new Student();
s.setName("XiaoMing");
s.setAge(17);
s.setScore(87.5);
在上面的代碼中,使用默認建構式創建了一個Student物件,在物件創建出來之后,還設定了Student的name、age、score這三個屬性,那么,這種需求要怎么在ByxContainer中實作呢?
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");
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/260242.html
標籤:Java
上一篇:Go string 一清二楚
下一篇:云原生系列3 pod核心欄位
