Java工厂模式应用

        之前在项目中遇到这样一种情景:代码中有一个共用的任务处理模块,不同的数据会通过唯一键(任务名称和key fields)全部存入公共任务表里,然后在同步模块通过任务名称去获取相应的任务进行同步处理。

        在存入公共任务表之前,不同的任务线都会进行各自的逻辑处理,而且基本上不存在共用的代码,所以在这里考虑建一个工厂类,由Spring注入一个Map<String, interface>,String对应的各个任务的名称,interface对应的是每个任务的处理接口。e.g.

<bean id="linkingDetectService" class="cn.vobile.service.linkingdetect.LinkingDetectServiceImpl">
		<property name="taskPriority" ref="normal" />
		<property name="commonTaskService" ref="commonTaskService" />
		<property name="gson" ref="gson" />
	</bean>
	
	<bean id="reclaimMatchSubscriptionService" class="cn.vobile.service.matchsubscription.reclaim.ReclaimMatchSubscriptionServiceImpl">
		<property name="taskPriority" ref="normal" />
		<property name="matchSubscriptionService" ref="matchSubscriptionService"/>
		<property name="gson" ref="gson" />
		<property name="matchedVideoService" ref="matchedVideoCommonService" />
		<property name="transactionTemplate" ref="masterTransactionTemplate" />
	</bean>
	
	<bean id="commonTaskFactory" class="cn.vobile.service.commontask.CommonTaskFactory">
		<property name="serviceMap">
			<map>
				<entry key="linkingDetect"><ref bean="linkingDetectService"/></entry>
				<entry key="reclaimMatchSubscription"><ref bean="reclaimMatchSubscriptionService"/></entry>
			</map>
		</property>
	</bean>

工厂类CommonTaskFactory的代码如下:

public class CommonTaskFactory {
	private Map<String, AbstractCommonService> serviceMap;
	
	/**
	 * Create a task service by taskName.
	 * 
	 * @param serviceName
	 * @return
	 */
	public AbstractCommonService create(String taskKey){
		return serviceMap.get(taskKey);
	}
	
	/**
	 * 
	 * @param serviceMap
	 */
	public void setServiceMap(Map<String, AbstractCommonService> serviceMap) {
		this.serviceMap = serviceMap;
	}
	
}

接口AbstractCommonService定义如下:

public interface AbstractCommonService {
	
	/**
	 * save a task to workingCommonTask
	 * 
	 * @param matchedVideo
	 * @param taskName
	 * @param matchType
	 * @param priority
	 */
	void addWorkingTask(MatchedVideo matchedVideo, CommonTaskName taskName, MatchType matchType);
}

工厂类方法调用代码示例如下:

AbstractCommonService linkingService = commonTaskFactory.create(CommonTaskKey.LINKINGDETECT.getCode());
linkingService.addWorkingTask(matchedVideo, CommonTaskName.SYNC_ADD_VIDEO_TO_TAISAN, null);

注:另外还有一种场景,各种任务存入公共任务表之前也许会存在很多的冗余代码(有很多的代码逻辑都是基本相同的),那么此时可以写一个抽象类(实现接口AbstractCommonService),把共用的代码写在该类中(每个任务线之间不同的部分可以使用抽象方法实现),然后各自不同的部分在各自的service类(继承抽象类)中实现父类中的抽象方法。代码如下:

<bean id="abstractCommonTaskService" class="cn.vobile.service.commontask.AbstractCommonTaskService" abstract="true">
        <property name="commonTaskService" ref="commonTaskService" />
        <property name="gson" ref="gson" />
    </bean>
    
    <bean id="linkingDetectService" class="cn.vobile.service.linkingdetect.LinkingDetectServiceImpl" parent="abstractCommonTaskService">
        <property name="taskPriority" value="normal" />
    </bean>
    
    <bean id="reclaimMatchSubscriptionService" class="cn.vobile.service.matchsubscription.reclaim.ReclaimMatchSubscriptionServiceImpl" parent="abstractCommonTaskService">
        <property name="taskPriority" value="normal" />
        <property name="matchSubscriptionService" ref="matchSubscriptionService"/>
        <property name="matchedVideoService" ref="matchedVideoCommonService" />
    </bean>
    
    <bean id="commonTaskFactory" class="cn.vobile.commontask.CommonTaskFactory">
        <property name="serviceMap">
            <map>
                <entry key="linking_detect_taisan"><ref local="linkingDetectService"/></entry>
                <entry key="match_subscription_reclaim"><ref local="reclaimMatchSubscriptionService"/></entry>
            </map>
        </property>
    </bean>

抽象类AbstractCommonTaskService代码如下:

public abstract class AbstractCommonTaskService<T extends CommonTaskParams> implements AbstractCommonService<T> {
    protected static final Logger logger = Logger.getLogger(AbstractCommonTaskService.class);
    protected CommonTaskService commonTaskService;
    protected TaskPriority taskPriority = TaskPriority.NORMAL;
    protected Gson gson;
    
    /**
     * @see cn.vobile.service.commontask.AbstractCommonService#addWorkingTask(cn.vobile.service.commontask.CommonTaskParams, cn.vobile.enums.CommonTaskName)
     */
    @Override
    public void addWorkingTask(T params, CommonTaskName taskName) {
        saveWorkingTask(params, taskName, taskPriority);
    }

    public void saveWorkingTask(T params, CommonTaskName taskName, TaskPriority priority) {
        Assert.notNull(params, "CommonTaskParams must not be null");
        Assert.notNull(taskName, "CommonTaskName must not be null");
        Assert.notNull(priority, "TaskPriority must not be null");

        if (isServiceToDeal(taskName)) {
            String uniqueKey = new MD5().MD5(uniqueKey(params));
            WorkingCommonTask oldTask = commonTaskService.getWorkingTaskByNameAndKey(taskName, uniqueKey);
            if (isAddToWorkingTask(oldTask)) {
                WorkingCommonTask task = new WorkingCommonTask();
                task.setCompanyId(params.getCompanyId());
                task.setTaskName(taskName.getCode());
                task.setUniqueKey(uniqueKey);
                task.setRetrievalField(retrievalField(params));
//                task.setExtraInfo("");
                task.setRetryCount(0);
                task.setTaskPriority(priority.getCode());
                task.setTaskStatus(CommonTaskStatus.CREATED.getCode());
                task.setTimeout(0);
                commonTaskService.saveWorkingTask(task, getBiz(params));
            }
        }
    }
    
    protected abstract String uniqueKey(T params);
    
    protected boolean isAddToWorkingTask(WorkingCommonTask oldTask) {
        return oldTask == null;
    }
    
    protected abstract String retrievalField(T params);
    
    protected abstract String getBiz(T params);
    
    protected abstract boolean isServiceToDeal(CommonTaskName taskName);
    
    public void setCommonTaskService(CommonTaskService commonTaskService) {
        this.commonTaskService = commonTaskService;
    }
    
    public void setTaskPriority(String taskPriority) {
        this.taskPriority = TaskPriority.getByCode(taskPriority);
    }

    public void setGson(Gson gson) {
        this.gson = gson;
    }
}

实现类代码(e.g.ReclaimMatchSubscriptionServiceImpl)如下:

public class ReclaimMatchSubscriptionServiceImpl extends AbstractCommonTaskService<MatchedInfoParams> {
    private static final Logger logger = Logger.getLogger(ReclaimMatchSubscriptionServiceImpl.class);
    private MatchSubscriptionService matchSubscriptionService;
    private MatchedVideoService matchedVideoService;
    
    /**
     * @see cn.vobile.service.commontask.AbstractCommonTaskService#addWorkingTask(cn.vobile.service.commontask.CommonTaskParams, cn.vobile.enums.CommonTaskName)
     */
    @Override
    public void addWorkingTask(MatchedInfoParams params, CommonTaskName taskName) {
        MatchSubscriptionInfo matchSubscriptionInfo = matchSubscriptionService.getMatchSubscriptionInfoFromCache(params.getCompanyId(), params.getTrackingWebsiteId());
        if (null == matchSubscriptionInfo) {
            // logger.warn("Unsupported matchSubscription: companyId=" + companyId + ", websiteId=" + websiteId);
            return;
        }
        
        super.addWorkingTask(params, taskName);

        // sync history matches
        if (!matchSubscriptionInfo.isSyncedHistoryMatches()) {
            if (matchSubscriptionService.setSyncedHistoryMatchesFlag(matchSubscriptionInfo.getId())) {
                matchSubscriptionInfo.setSyncedHistoryMatches(true);// change the syncedHistoryMatches flag to true in cache

                List<Integer> matchIds = null;
                if (MatchType.MATCHED_VIDEO == params.getMatchType()) {
                    matchIds = matchedVideoService.getMatchedVideoRightIds(params.getCompanyId(), params.getTrackingWebsiteId());
                }

                if (CollectionUtils.isNotEmpty(matchIds)) {
                    matchIds.remove(new Integer(params.getMatchId()));
                    saveHistoryMatches(params, CommonTaskName.SYNC_ADD_MATCH_TO_RECLAIM, matchIds);
                }
            }
        }
    }
    
    private void saveHistoryMatches(final MatchedInfoParams params, final CommonTaskName taskName, final List<Integer> matchIds) {
        new Thread() {
            @Override
            public void run() {
                MatchedInfoParams clonedParams = params.clone();
                for (final Integer matchId : matchIds) {
                    try {
                        clonedParams.setMatchId(matchId);
                        saveWorkingTask(clonedParams, taskName, TaskPriority.LOW);
                    } catch (Exception e) {
                        logger.error("Save history matches to working task failed: matchedId=" + matchId + ", companyId=" + params.getCompanyId() + ", taskName=" + taskName
                                + ", matchType=" + params.getMatchType(), e);
                    }
                }
            }
        }.start();
    }

    /**
     * @see cn.vobile.service.commontask.AbstractCommonTaskService#uniqueKey(cn.vobile.service.commontask.CommonTaskParams)
     */
    @Override
    protected String uniqueKey(MatchedInfoParams params) {
        return params.getMatchType().getCode() + "_" + params.getMatchId() + "_" + params.getCompanyId();
    }

    @Override
    protected boolean isAddToWorkingTask(WorkingCommonTask oldTask) {
        boolean ret = false;
        CommonTaskName taskName = null;
        if (null != oldTask) {
            taskName = CommonTaskName.getByCode(oldTask.getTaskName());
        }
        if (null == oldTask
                || (taskName == CommonTaskName.SYNC_UPDATE_MATCH_TO_RECLAIM && CommonTaskStatus.STARTED == oldTask.getTaskStatusEnum() && !commonTaskService.updateWorkingTaskStatus(taskName,
                        oldTask.getUniqueKey(), CommonTaskStatus.STARTED, CommonTaskStatus.CREATED))) {
            ret = true;
        }
        return ret;
    }

    /**
     * @see cn.vobile.service.commontask.AbstractCommonTaskService#retrievalField(cn.vobile.service.commontask.CommonTaskParams)
     */
    @Override
    protected String retrievalField(MatchedInfoParams params) {
        return params.getMatchType().getCode() + "_" + params.getMatchId();
    }

    /**
     * @see cn.vobile.service.commontask.AbstractCommonTaskService#getBiz(cn.vobile.service.commontask.CommonTaskParams)
     */
    @Override
    protected String getBiz(MatchedInfoParams params) {
        MatchSubscriptionBizData bizData = new MatchSubscriptionBizData();
        bizData.setMatchType(params.getMatchType().getCode());
        bizData.setMatchId(params.getMatchId());
        return gson.toJson(bizData);
    }

    @Override
    protected boolean isServiceToDeal(CommonTaskName taskName) {
        return taskName.getServiceName() == ServiceName.MATCH_SUBSCRIPTION;
    }

    public void setMatchSubscriptionService(MatchSubscriptionService matchSubscriptionService) {
        this.matchSubscriptionService = matchSubscriptionService;
    }

    public void setMatchedVideoService(MatchedVideoService matchedVideoService) {
        this.matchedVideoService = matchedVideoService;
    }
}

工厂类CommonTaskFactory代码如下:

public class CommonTaskFactory {
    private Map<String, AbstractCommonService<CommonTaskParams>> serviceMap;

    /**
     * Create a task service by taskName && do the addWorkingTask method.
     * @param paramList
     */
    public void saveCommonTask(CommonTaskParams params, CommonTaskName[] taskNames) {
        saveCommonTask(params, Arrays.asList(taskNames));
    }

    public void saveCommonTask(CommonTaskParams params, List<CommonTaskName> taskNames) {
        Assert.notNull(params, "CommonTaskParams must not be null");
        Assert.notEmpty(taskNames, "CommonTaskNames must not be empty");
        for (CommonTaskName taskName : taskNames) {
            saveCommonTask(params, taskName);
        }
    }

    public void saveCommonTask(CommonTaskParams params, CommonTaskName taskName) {
        Assert.notNull(params, "CommonTaskParams must not be null");
        Assert.notNull(taskName, "CommonTaskName must not be null");
        AbstractCommonService<CommonTaskParams> service = serviceMap.get(taskName.getServiceModule());
        Assert.notNull(service, "can not find Processor!");
        service.addWorkingTask(params, taskName);
    }
    
    /**
     * 
     * @param serviceMap
     */
    public void setServiceMap(Map<String, AbstractCommonService<CommonTaskParams>> serviceMap) {
        this.serviceMap = serviceMap;
    }
    
}
<strong><span style="color:#CC0000;">AbstractCommonService<CommonTaskParams> service = serviceMap.get(taskName.getServiceModule());</span></strong>
这种方式是以父类的引用来实例化子类对象,e.g. 父类A和子类B
A a=new B()
在这种方式中NEW的是B,内存中创建的空间其实是A+B,其中A+B中的B,指的是B中继承过来以外的部分,即B新增的属性和方法。因为声明的与内存中的不一致,所以视为多态!


接口AbstractCommonService代码如下:

public interface AbstractCommonService<T extends CommonTaskParams> {
    
    /**
     * save a task to workingCommonTask
     * 
     * @param param
     */
    void addWorkingTask(T params, CommonTaskName taskName);
}

方法的调用如下:

commonTaskFactory.saveCommonTask(new MatchedVideoParams(matchedVideo), new CommonTaskName[] { CommonTaskName.SYNC_ADD_MATCH_TO_RECLAIM, CommonTaskName.SYNC_ADD_VIDEO_TO_TAISAN });

将addWorkingTask方法中所需要用到T(MatchedVideoParams)中的参数,全部在T(MatchedVideoParams)初始化的时候定义好(在这使用接口),在这里不直接使用MatchedVideo(元Bean)作为T的原因是有一些参数是需要进行clone或者多个元字段进行拼接的, 代码如下:

public class MatchedVideoParams implements MatchedInfoParams {
    private final MatchedVideo matchedVideo;

    /**
     * @param matchedVideo
     */
    public MatchedVideoParams(MatchedVideo matchedVideo) {
        Assert.notNull(matchedVideo, "MatchedVideo must not be null");
        this.matchedVideo = matchedVideo;
    }

    /**
     * @see cn.vobile.service.commontask.CommonTaskParams#getCompanyId()
     */
    @Override
    public int getCompanyId() {
        return matchedVideo.getCompanyId();
    }

    /**
     * @see cn.vobile.service.commontask.MatchedInfoParams#setMatchId(int)
     */
    @Override
    public void setMatchId(int matchId) {
        matchedVideo.setId(matchId);
    }

    /**
     * @see cn.vobile.service.commontask.MatchedInfoParams#getMatchId()
     */
    @Override
    public int getMatchId() {
        return matchedVideo.getId();
    }

    /**
     * @see cn.vobile.service.commontask.MatchedInfoParams#getTrackingWebsiteId()
     */
    @Override
    public int getTrackingWebsiteId() {
        return matchedVideo.getTrackingWebsiteId();
    }

    /**
     * @see cn.vobile.service.commontask.MatchedInfoParams#getKeyId()
     */
    @Override
    public String getKeyId() {
        return matchedVideo.getKeyId();
    }

    /**
     * @see cn.vobile.service.commontask.MatchedInfoParams#getMatchType()
     */
    @Override
    public MatchType getMatchType() {
        return MatchType.MATCHED_VIDEO;
    }

    /**
     * @see cn.vobile.service.commontask.MatchedInfoParams#clone(int)
     */
    @Override
    public MatchedVideoParams clone() {
        MatchedVideo mv = new MatchedVideo();
        BeanUtils.copyProperties(matchedVideo, mv);
        return new MatchedVideoParams(mv);
    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值