思考充血模式下,domain object 对 repository 的依赖的解耦方法。实际上在HTML,java swing 等中都已经给出的解决方法,就是 event。
想到解耦在GOF设计模式中最熟悉的就是 observer模式和command模式,其实两者区别不大。所以以observer模式来实现。 在java.util中就已经有了observer的实现,但是太简单了,不太适合这种复杂的domain,特别是在有多种不同的事件触发的情况.所以决定重写Observable.
public abstract class DomainObservable implements java.io.Serializable {
private HashMap<String, Collection> observerMap = new HashMap<String, Collection>();
public HashMap<String, Collection> getObserverMap() {
return observerMap;
}
public void setObserverMap(HashMap<String, Collection> observerMap) {
if(observerMap != null)
{
this.observerMap = observerMap;
}
}
public void addObserver(String eventType,DomainObserver domainObserver) {
if (domainObserver == null)
{
throw new NullPointerException();
}
if(observerMap.containsKey(eventType))
{
observerMap.get(eventType).add(domainObserver);
}
else
{
Collection<DomainObserver> observers = new ArrayList<DomainObserver>();
observers.add(domainObserver);
observerMap.put(eventType, observers);
}
}
public void deleteObserver(String eventType,DomainObserver o) {
Collection<DomainObserver> observers = observerMap.get(eventType);
if(observers != null)
{
observers.remove(o);
}
}
public void deleteObservers() {
observerMap.clear();
}
public void notifyObservers(String eventType)
{
this.notifyObservers(eventType, null);
}
public void notifyObservers(String eventType,Object arg) {
Collection<DomainObserver> observers = observerMap.get(eventType);
if(observers != null)
{
Iterator<DomainObserver> ita = observers.iterator();
while(ita.hasNext())
{
DomainObserver domainObserver = ita.next();
ObserverValueObject observerValueObject = domainObserver.getObserverValueObject();
if(observerValueObject != null)
{
observerValueObject.init(this,arg);
}
domainObserver.update(this,eventType,arg);
}
}
}
}
这样在domain object中可以发出不同类型的event,observer也可以针对不同的event来进行观察.
在来看observer interface,如下
public interface DomainObserver {
/**
* 当被观察者对象发生变化引起事件的时候,调用
* @param demainObservable 被观察者
* @param eventType 被观察者事件类型
* @param arg 被观察者传递的值
*/
public void update(DomainObservable demainObservable,String eventType,Object arg);
}
对于observer,我定义成为了去完成某项功能的client。为了完成功能,需要两个重要方面,服务和数据。服务好说 IOC一下就可以了。但是对于数据,就需要做一些操作了,目的是为了让observer与observable解耦,同时对observer进行依赖注入。所以怎样从domain object 中抽取出 observer所需要的数据,就成了observer value object的任务了。
看如下value object 接口:
public interface ObserverValueObject extends java.io.Serializable{
/**
* 根据被观察者生成观察者所需要的值对象
* @param domainObservable
* @param arg
*/
public void init(DomainObservable domainObservable,Object arg);
}
然后对observer interface 进行改进
public interface DomainObserver {
/**
* 返回观察者的值对象
* @return
*/
public ObserverValueObject getObserverValueObject();
/**
* 当被观察者对象发生变化引起事件的时候,调用
* @param demainObservable 被观察者
* @param eventType 被观察者事件类型
* @param arg 被观察者传递的值
*/
public void update(DomainObservable demainObservable,String eventType,Object arg);
}
另外,某些情况下,被观察者需要知道观察者做事情后的结果,所以需要给出一些回调方法,如下 3种回调
/**
* 回掉 具体方法 获取返回值
* @param eventType
* @param methodName
* @param args
* @return
* @throws Throwable
*/
public Object callbackDomainObserver(String eventType,String methodName,Object[] args)
{
Object result = null;
boolean isFindMethod = false;
Collection<DomainObserver> observers = observerMap.get(eventType);
if(observers != null)
{
Iterator<DomainObserver> ita = observers.iterator();
while(ita.hasNext())
{
DomainObserver domainObserver = ita.next();
/**
* 构建参数对象CLASS
*/
Class[] parameterTypes = null;
if(args != null)
{
parameterTypes = new Class[args.length];
for(int i = 0;i<args.length;i++)
{
parameterTypes[i] = args[i].getClass();
}
}
Method method = null;
/**
* 取得相同名称的方法 如果没有 就是NULL
*/
try {
method = domainObserver.getClass().getMethod(methodName, parameterTypes);
} catch (Exception e) {
}
if(method != null)
{
try {
result = method.invoke(domainObserver, args);
isFindMethod = true;
break;
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
if(e.getTargetException() instanceof SystemException)//如果是系统业务异常
{
throw (SystemException)e.getTargetException();
}
else//否则是程序错误异常
{
throw new RuntimeException(e.getTargetException());
}
}
}
}
}
if(isFindMethod)
{
return result;
}
else
{
throw new RuntimeException("System Observer Error:Domain Object("+this.getClass().getName()+") needs Observer to observe event of "+eventType+" and Need CallBack method "+methodName);
}
}
public Collection<DomainObserver> callbackDomainObserver(String eventType)
{
return observerMap.get(eventType);
}
public Collection<ObserverValueObject> callbackObserverValueObject(String eventType)
{
Collection<DomainObserver> observers = observerMap.get(eventType);
if(observers != null)
{
Collection<ObserverValueObject> valueObjects = new ArrayList<ObserverValueObject>();
Iterator<DomainObserver> ita = observers.iterator();
while(ita.hasNext())
{
valueObjects.add(ita.next().getObserverValueObject());
}
return valueObjects;
}
else
{
return null;
}
}
在我的项目中,第一种回调(回调方法)用的比较多,但这里有一些耦合。本来想再利用一种KEY-VALUE配置的方式来解耦,但是想想,这样做起来,返回代码阅读困难度增加不少,就放弃了。这里算是一个小的不足,看各位有没有更改好的解决办法。
到了这里,大部分代码工作已经完成,下面就需要整合了。其实里面最关键也最重要的就是怎么样把observer注入到 被观察者中。
首先配置observer value object 和 observer --- spring 里面很好配置,注意:有些observer可以直接配置成 单例,但是有些需要给出回调方法的observer 不能配置成 单例 。
然后是把observer注入到被观察者中。利用aspectJ(spring 里面已经整合过)的LTW功能注入。
下面给出个例子吧
domain object
@Configurable
public class BrandDomain extends DomainObservable{
private String brandno;
private String brandName;
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getBrandno() {
return brandno;
}
public void setBrandno(String brandno) {
this.brandno = brandno;
}
public void addBrandDomain(BrandValueObject valueObject)
{
if(!this.checkSameObjectExist(valueObject.getBrandno()))
{
this.setBrandno(valueObject.getBrandno());
this.setBrandName(valueObject.getBrandName());
this.notifyObservers("save");
}
else
{
throw new BusinessException("品牌编码已经存在");
}
}
public void editBrandDomain(BrandValueObject valueObject)
{
this.setBrandName(valueObject.getBrandName()); this.notifyObservers("update");
}
protected boolean checkSameObjectExist(Object keyword)
{
this.notifyObservers("checkSameObject", keyword);
return (Boolean) this.callbackDomanObserver("checkSameObject", "isExistSameObject", null);
}
public void deleteBrand()
{
this.notifyObservers("delete");
}
}
配置文件
<bean class="cn.com.dbSale.server.business.domain.basisDomain.productDomain.brandDomain.BrandDomain" scope="prototype" >
<property name="observerMap">
<map key-type="java.lang.String" value-type="java.util.Collection">
<entry key="save">
<list value-type="java.util.ArrayList">
<ref bean="saveObjectObserver"/>
</list>
</entry>
<entry key="update">
<list value-type="java.util.ArrayList">
<ref bean="updateObjectObserver"/>
</list>
</entry>
<entry key="delete">
<list value-type="java.util.ArrayList">
<ref bean="deleteObjectObserver"/>
</list>
</entry>
<entry key="checkSameObject">
<list value-type="java.util.ArrayList">
<ref bean="checkSameObjectObserver"/>
</list>
</entry>
</map>
</property>
</bean>
<bean id="saveObjectObserver" class="cn.com.dbSale.server.business.observer.observerInterface.SaveObjectObserver">
<property name="repositoryInterface">
<ref local="repositoryInterface"/>
</property>
</bean>
<bean id="updateObjectObserver" class="cn.com.dbSale.server.business.observer.observerInterface.UpdateObjectObserver">
<property name="repositoryInterface">
<ref local="repositoryInterface"/>
</property>
</bean>
<bean id="deleteObjectObserver" class="cn.com.dbSale.server.business.observer.observerInterface.DeleteObjectObserver">
<property name="repositoryInterface">
<ref local="repositoryInterface"/>
</property>
</bean>
<bean id="checkSameObjectObserver" class="cn.com.dbSale.server.business.observer.observerInterface.CheckSameObjectObserver" scope="prototype">
<property name="repositoryInterface">
<ref local="repositoryInterface"/>
</property>
</bean>
以上是一个最简单的例子,还算是表达出了基本意思。
对于复杂的流程可以通过发布事件 达到流程可配置.
增、删、改 这3个观察者 可以适注入到所有DOMAIN 对象中。
另外observer value object 的用法,没有给出,各位可以自己试试
整个DOMAIN EVENT 的源文件 都在附件里面,代码不多。
本人第一次网上发文章,如有不足,多多关照!
还有,如果各位需要observer 与 被观察者 异步操作,可以修改 AbstractObservable 代码 实现异步观察
分享到:
相关推荐
maven-repository-metadata-3.0.jar
《PyPI官网下载:service_repository-0.1.0-py3-none-any.whl》 在Python的世界里,PyPI(Python Package Index)是官方的软件仓库,它为开发者提供了发布和分享Python软件包的平台。PyPI上的资源广泛且多样化,...
领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法论,由Eric Evans在其同名著作中提出,旨在帮助开发者更好地理解和处理复杂的业务逻辑,通过深入挖掘领域知识来构建高质量的软件系统。DDD的核心是...
标题“repository.xbmc-addons-chinese-1.2.1.zip”揭示了这是一个与XBMC(Xbox Media Center)相关的软件资源包,版本号为1.2.1,并且是针对中文用户定制的。XBMC是一款开源的媒体中心软件,后来更名为Kodi,允许...
Repository文件通常包含元数据、插件的安装包以及更新信息,使得用户能通过Kodi的界面方便地安装和更新这些插件。 为了充分利用这个中文插件库,用户需要在Kodi中安装它。首先,用户需要将“repository.xbmc-addons...
综上所述,"elasticsearch-repository-oss-6.7.0"插件利用了上述库,实现了Elasticsearch与阿里云OSS的无缝集成,提供了一种可靠的数据备份和恢复解决方案。在实际部署中,用户需要正确配置Elasticsearch的插件和OSS...
标题中的"repository.xbmc-addons-chinese-2.0.0.zip"是一个针对KODI媒体中心的中文插件库的压缩包,版本号为2.0.0。这个压缩包包含了多款专为中国用户设计的KODI插件,旨在提升KODI在中文环境下的用户体验和功能...
《C#-DDD领域驱动设计-曹建》是关于使用C#编程语言实践领域驱动设计(Domain-Driven Design,简称DDD)的一个项目。领域驱动设计是一种软件开发方法,它强调以业务领域为中心进行软件设计,将复杂的业务逻辑转化为可...
【标题】"smart-lottery抽奖系统基于COLA架构采用DDD领域驱动中四层架构" 描述了这个项目的核心设计原则和技术栈。首先,我们要理解COLA架构和DDD(领域驱动设计)的概念。 COLA(Clean Architecture On Layers,...
《深入解析base-repository-authorization-service源码》 在当今的软件开发中,授权服务扮演着至关重要的角色,它确保了系统的安全性和用户访问权限的正确管理。"base-repository-authorization-service-源码.rar...
领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法,它强调通过深入理解和建模业务领域来驱动软件的设计和开发。DDD2019领域驱动设计大会是一次专门探讨这一主题的会议,旨在帮助开发者更好地应用...
领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法,它强调以业务领域为中心进行系统设计,将复杂的业务逻辑转化为清晰的模型,从而提高软件的可读性、可维护性和可扩展性。NopCommerce是一款开源的...
仓储Repository在领域驱动设计(DDD)中扮演着重要的角色,它是连接业务逻辑层(领域层)与数据访问层(基础设施层)的关键组件。仓储的主要目的是抽象出数据访问的细节,使得领域模型可以专注于业务规则和逻辑,而...
领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法论,旨在通过将业务领域模型作为软件开发的核心,来解决复杂系统的设计和实现问题。在C#开发中,DDD可以帮助开发者更好地理解和处理复杂的业务逻辑...
领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法,强调以业务领域为中心进行系统设计,将复杂的业务逻辑转化为清晰的模型。在“基于DDD领域驱动设计通用后台权限系统”中,我们首先需要理解DDD的...
在《领域驱动设计(Domain_Driven_Design_C_Sharp)》这本书中,作者深入探讨了如何在C#环境下实践DDD。 1. **领域模型**:领域模型是DDD的核心,它代表了业务领域的概念、规则和流程。在C#中,我们可以通过定义...
标题中的"Repository-UOW-Sample-master_C#"表明这是一个关于C#编程语言的示例项目,主要涉及Repository模式和Unit of Work(工作单元)模式。Repository模式是设计模式中的一种,常用于数据访问层,它为业务逻辑层...
标签:archiva-scheduler-repository-api-2.0.0-sources.jar,archiva,scheduler,repository,api,2.0.0,sources,jar包下载,依赖包