DCI的AspectJ实现

文章作者写了使用多个框架实现DCI模式(Data Context Interaction)的文章,这次他使用aspectJ(Spring)谈如何实现DCI,他的结论是比Qi4j要清晰一些。

下面是Qi4j的实现代码:


SingletonAssembler assembler = new SingletonAssembler() {
public void assemble(ModuleAssembly module) throws AssemblyException {
module.addEntities(TaskEntity.class, UserEntity.class);//加入任务数据实体 和用户数据实体
module.addServices(MemoryEntityStoreService.class, UuidIdentityGeneratorService.class);
//加入服务
}
};

UnitOfWork uow = assembler.unitOfWorkFactory().newUnitOfWork();

TaskEntity task = uow.newEntity(TaskEntity.class);

EntityBuilder<UserEntity> builder = uow.newEntityBuilder(UserEntity.class);
builder.instanceFor(AssigneeData.class).name().set(
"Rickard");
UserEntity user = builder.newInstance();

{
//根据用户名为"Rickard "产生一个场景
InboxContext inbox = new InboxContext(user, user);
//与任务结合
inbox.assign(task);
}

uow.complete();

以上代码主要表达意思是:给一个名叫"Rickard "的用户分配一个任务。作者认为上面代码很多严重依赖反射,影响性能,而且这些实体类不是普通的POJO类,和Spring之类框架整合起来困难。

下面是和aspectJ的过程,第一步定义几种分配行为,作为实体的元注解使用:


public interface Assignments {

void assign(Assignable assignable, Assignee assignee);

List<Assignable> assignments();
}

public interface Assignable {

void assignTo(Assignee assignee);
}

public interface Assignee {

String assigneeName();
}

以下是参与者的实体数据:

@AssignmentsRole //分配者
public class Project {
}

@AssignableRole
//被分配者
public class Task {
}

@AssignmentsRole
@AssigneeRole
public class User {

public User(String name) {
setName(name);
}
}

下面是关键的建立一个aspect类:


aspect AssignableImpl {

declare parents: (@AssignableRole *) implements Assignable;

private Assignee Assignable.assignee;

//分配动作
public void Assignable.assignTo(Assignee assignee) {
// No object schizophrenia - this reference is to the entity itself.
this.assignee = assignee;
System.out.println(assignee.assigneeName());
}
}

下面是场景对象

public class InboxContext {

private Assignments assignments;
private Assignee assignee;

public InboxContext(Assignments assignments, Assignee assignee) {
this.assignments = assignments;
this.assignee = assignee;
}

public void assign(Assignable assignable) {
assignments.assign(assignable, assignee);
}
}

(banq疑问:一般DCI有了场景 数据就可以了,这里多出一个aspectj,难道比qi4j要简单吗?)

最后是实现DCI混合客户端代码:


Task task = new Task();
User user = new User("Rickard");

InboxContext inbox = new InboxContext(user, user);
//给用户Rickard分配任务
inbox.assign(task);

System.out.println(
"Nr of assignments: " + user.assignments().size());

Project project = new Project();
Task task2 = new Task();

//获得场景
inbox = new InboxContext(project, user);
//给某个项目中的用户Rickard分配任务
inbox.assign(task2);

System.out.println(
"Nr of assignments: " + project.assignments().size());

User Task都是没有继承任何类的POJO,可以被序列化,也可以在spring.xml配置中配置。


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id=
"userRickard" class="net.sourceforge.dciaspectj.example1.entity.User">
<constructor-arg index=
"0" value="Rickard" />
</bean>

<bean id=
"project" class="net.sourceforge.dciaspectj.example1.entity.Project" />

<bean id=
"task1" class="net.sourceforge.dciaspectj.example1.entity.Task" />

<bean id=
"task2" class="net.sourceforge.dciaspectj.example1.entity.Task" />

<bean id=
"userInbox" class="net.sourceforge.dciaspectj.example1.context.InboxContext">
<constructor-arg index=
"0" ref="userRickard" />
<constructor-arg index=
"1" ref="userRickard" />
</bean>

<bean id=
"projectInbox" class="net.sourceforge.dciaspectj.example1.context.InboxContext">
<constructor-arg index=
"0" ref="project" />
<constructor-arg index=
"1" ref="userRickard" />
</bean>
</beans>

原文:
DCI in AspectJ | Javalobby
案例代码:http://sourceforge.net/projects/dci-in-aspectj/files/dci_in_aspectj-1.0.0-src.zip/download

请注意,文中使用配置了实体类User等创建时,并给给User对象赋值为"Rickard",这只是一个演示,关键是:实战中:User或Project的数据是从数据库中获得的。

关键是:我们已经注意到,在Spring管理的业务层,已经对实体类加了@AssignmentsRol之类元注解,也就是不能不管模型实体类了,下面的问题是:模型实体类的对象生存在哪里?

http://www.jdon.com/jivejdon/thread/39885/15#23132346