赞助

设计模式--行为模式--模板方法

行为模型:模板方法

设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关 如:去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现

模式定义与特点

  • 该模式的主要优点
    1. 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
    2. 它在父类中提取了公共的部分代码,便于代码复用。
    3. 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
  • 该模式主要缺点
    1. 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。
    2. 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度
    3. 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。

模式的应用实例

 

 

  • 如下代码,根据业务需求,手机号注册以及账密注册两种方式,注册流程都相同,现业务的区别之处在于存储redis的namespace不同,因此封装了不变部分,扩展可变部分,实现模板方法模式
import com.dadi01.scrm.foundation.model.error.ErrorEnum;
import com.dadi01.scrm.foundation.model.exception.ScrmException;
import com.dadi01.scrm.foundation.utils.date.DateRelatedUtils;
import com.dadi01.scrm.service.member.api.dto.request.AbstractRegisterRq;
import com.dadi01.scrm.service.member.provider.domain.MemberDomain;
import com.dadi01.scrm.service.member.provider.factory.AuthenticatorFactory;
import com.dadi01.scrm.service.member.provider.service.base.IBaseMemberService;
import com.dadi01.scrm.service.member.provider.util.CheckModelUtils;
import com.dadi01.scrm.service.member.provider.util.KeyGenerateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lviter
 */
@Component
public abstract class RegisterTemplate {

    private final AuthenticatorFactory authenticatorFactory;
    private final IBaseMemberService baseMemberService;
    private final KeyGenerateUtil keyGenerateUtil;

    public RegisterTemplate(AuthenticatorFactory authenticatorFactory, IBaseMemberService baseMemberService, KeyGenerateUtil keyGenerateUtil) {
        this.authenticatorFactory = authenticatorFactory;
        this.baseMemberService = baseMemberService;
        this.keyGenerateUtil = keyGenerateUtil;
    }

    /**
     * 注册统一模板方法
     *
     * @param tenantId
     * @param account
     * @param abstractRegisterRq
     */
    public void registerTemplate(Integer tenantId, String account, AbstractRegisterRq abstractRegisterRq) {
        Long cacheSize = getCache(tenantId, account);
        if (null == cacheSize || cacheSize <= 0) {
            //创建账号
            Long id = generateKey();
            saveMember(id, abstractRegisterRq);
            //放入缓存
            saveCache(abstractRegisterRq.getTenantId(), account, id);
        } else {
            registerMemberDomainValidate(cacheSize, tenantId);
        }

    }


    /**
     * 生成分布式主键
     *
     * @return
     */
    public Long generateKey() {
        return keyGenerateUtil.generate();
    }


    /**
     * 获取缓存内手机号/账号对应的id
     *
     * @param tenantId
     */
    public Long getCache(Integer tenantId, String account) {
        return (Long) getLoginUserFromCache(tenantId).get(account);
    }

    /**
     * 结果存入缓存
     *
     * @param tenantId
     * @param account
     * @param id
     */
    public void saveCache(Integer tenantId, String account, Long id) {
        Map<String, Object> cache = new HashMap<>(2);
        cache.put(account, id);
        saveLoginUserToCache(tenantId, cache);
    }


    /**
     * 从缓存内获取hash集合
     *
     * @param tenantId
     * @return
     */
    public abstract Map<Object, Object> getLoginUserFromCache(Integer tenantId);

    /**
     * 存储缓存
     *
     * @param tenantId
     * @param cache
     */
    public abstract void saveLoginUserToCache(Integer tenantId, Map<String, Object> cache);

    /**
     * 保存会员信息
     *
     * @param id
     * @param abstractRegisterRq
     */
    public void saveMember(Long id, AbstractRegisterRq abstractRegisterRq) {
        MemberDomain memberDomain = new MemberDomain(id);
        BeanUtils.copyProperties(abstractRegisterRq, memberDomain);
        CheckModelUtils.checkField(memberDomain);
        if (StringUtils.isNotBlank(abstractRegisterRq.getBirth())) {
            DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            DateRelatedUtils.convertStringToLongDateString(abstractRegisterRq.getBirth());
            try {
                memberDomain.setBirth(fmt.parse(abstractRegisterRq.getBirth()));
            } catch (ParseException e) {
                throw new ScrmException(ErrorEnum.MEMBER_DATE_FORMAT_ERROR.build());
            }
        }
        baseMemberService.save(memberDomain);
    }


    /**
     * 校验账户
     *
     * @param id
     * @param tenantId
     */
    public void registerMemberDomainValidate(Long id, Integer tenantId) {
        authenticatorFactory.registerMemberDomainValidate(id, tenantId);
    }
}
import com.dadi01.scrm.foundation.model.constant.RedisConstant;
import com.dadi01.scrm.service.member.provider.factory.AuthenticatorFactory;
import com.dadi01.scrm.service.member.provider.service.base.IBaseMemberService;
import com.dadi01.scrm.service.member.provider.util.KeyGenerateUtil;
import com.dadi01.scrm.service.member.provider.util.RedisUtil;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author lviter
 */
@Component
public class PasswordRegister extends RegisterTemplate {

    private final RedisUtil redisUtils;

    public PasswordRegister(AuthenticatorFactory authenticatorFactory, IBaseMemberService baseMemberService, KeyGenerateUtil keyGenerateUtil, RedisUtil redisUtils) {
        super(authenticatorFactory, baseMemberService, keyGenerateUtil);
        this.redisUtils = redisUtils;
    }

    /**
     * 获取登录账户从缓存中是否存在
     *
     * @param tenantId
     * @return
     */
    @Override
    public Map<Object, Object> getLoginUserFromCache(Integer tenantId) {
        return redisUtils.hmget(RedisConstant.REDIS_PASSWORD_NAMESPACE.concat(String.valueOf(tenantId)));
    }


    /**
     * 保存账户到缓存内
     *
     * @param tenantId
     * @param memberPhoneCache
     */
    @Override
    public void saveLoginUserToCache(Integer tenantId, Map<String, Object> memberPhoneCache) {
        redisUtils.hmset(RedisConstant.REDIS_PASSWORD_NAMESPACE.concat(String.valueOf(tenantId)), memberPhoneCache);
    }
}
import com.dadi01.scrm.foundation.model.constant.RedisConstant;
import com.dadi01.scrm.service.member.provider.factory.AuthenticatorFactory;
import com.dadi01.scrm.service.member.provider.service.base.IBaseMemberService;
import com.dadi01.scrm.service.member.provider.util.KeyGenerateUtil;
import com.dadi01.scrm.service.member.provider.util.RedisUtil;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author lviter
 */
@Component
public class SmsRegister extends RegisterTemplate {
    private final RedisUtil redisUtils;

    public SmsRegister(AuthenticatorFactory authenticatorFactory, IBaseMemberService baseMemberService, KeyGenerateUtil keyGenerateUtil, RedisUtil redisUtils) {
        super(authenticatorFactory, baseMemberService, keyGenerateUtil);
        this.redisUtils = redisUtils;
    }

    @Override
    public Map<Object, Object> getLoginUserFromCache(Integer tenantId) {
        return redisUtils.hmget(RedisConstant.REDIS_PHONE_NAMESPACE.concat(String.valueOf(tenantId)));
    }

    @Override
    public void saveLoginUserToCache(Integer tenantId, Map<String, Object> cache) {
        redisUtils.hmset(RedisConstant.REDIS_PHONE_NAMESPACE.concat(String.valueOf(tenantId)), cache);
    }

}

 

posted @ 2021-01-29 12:07  念念不忘、  阅读(102)  评论(0编辑  收藏  举报