工作中常用的Java设计模式

127 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

策略模式

业务场景

根据传入参数的不同类型采取不同的解析方式

定义

策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。

使用
  • 一个接口或者抽象类,里面两个方法(一个方法匹配类型,一个可替换的逻辑实现方法)
  • 不同策略的差异化实现(就是说,不同策略的实现类)
  • 使用策略模式

1 一个接口,两个方法

//待实现的接口
public interface IDataBaseGranter {
  //获取类型
  String getGrantType();
  //设置连接属性
    void setUrlAndDriver(DataSourcesDTO dto);
}

//获取实现类的工厂
@Service
public class DataBaseGranterFactory {

    private final Map<String, IDataBaseGranter> GRANTER_POOL;

    @Autowired
    private DataBaseGranterFactory(List<IDataBaseGranter> dataBaseGranterList){
        GRANTER_POOL = dataBaseGranterList.stream().collect(Collectors.toMap(IDataBaseGranter::getGrantType, Function.identity(), (a, b) -> b));
    }

    //获取IDataBaseGranter
    public IDataBaseGranter getGranter(String grantType) {
        IDataBaseGranter tokenGranter = GRANTER_POOL.get(StrUtil.isBlank(grantType) ? JdbcConstants.MYSQL : grantType);
        if (tokenGranter == null) {
            throw new SecureException("no grantType was found");
        } else {
            return GRANTER_POOL.get(StrUtil.isBlank(grantType) ? JdbcConstants.MYSQL : grantType);
        }
    }
}

2 不同策略的不同实现

//Mysql实现
@Component
@AllArgsConstructor
public class MysqlGranter implements IDataBaseGranter {
    @Override
    public String getGrantType() {
        return JdbcConstants.MYSQL;
    }
    @Override
    public void setUrlAndDriver(DataSourcesDTO dto) {
        dto.setDriverName(JdbcConstants.MYSQL_DRIVER_6);
    }
}

//POSTGRESQL实现
@Component
@AllArgsConstructor
public class PostgresqlGranter implements IDataBaseGranter {
    @Override
    public String getGrantType() {
        return JdbcConstants.POSTGRESQL;
    }
    @Override
    public void setUrlAndDriver(DataSourcesDTO dto) {
        dto.setDriverName(JdbcConstants.POSTGRESQL_DRIVER);
    }
}

3 使用策略模式

@Service
@AllArgsConstructor
public class DataSourcesServiceImpl extends ServiceImpl<DataSourcesMapper, DataSources> implements IDataSourcesService {
  private final DataBaseGranterFactory dataBaseGranterFactory;
  
  public Boolean testConnection(DataSourcesDTO dto){
    //根据传参的类型选择map中对应的实现类
    IDataBaseGranter granter = dataBaseGranterFactory.getGranter(dto.getSourceType());
    granter.setUrlAndDriver(dto);
  }
}

责任链模式

业务场景

一层接着一层的业务逻辑,比如下订单,需要对订单的传参先进行非空校验,完成后进行安全校验等步骤,最后输出正确的结果,其中一步错误直接跳出。

定义

责任链模式为请求创建了一个接收者对象的链。执行链上有多个对象节点,每个对象节点都有机会(条件匹配)处理请求事务,如果某个对象节点处理完了,就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。

使用
  • 一个接口或者抽象类
  • 每个对象差异化处理
  • 对象链(数组)初始化(连起来)

抽象类

@Setter
@Getter
public abstract class AbstractHandler {
    //下一个对象
    private AbstractHandler nextHandler;

    //具体参数拦截逻辑
    public void filter(Request request, Response response){
        doFilter(request,response);
        if (Optional.ofNullable(getNextHandler()).isPresent()){
            getNextHandler().filter(request,response);
        }
    }

    abstract void doFilter(Request request, Response response);
}

差异化对象

@Component
@Order(1)
public class CheckParamFilterObject extends AbstractHandler{
    @Override
    void doFilter(Request request, Response response) {
        System.out.println("非空参数检查");
    }
}

@Component
@Order(2)
public class CheckSecurityFilterObject extends AbstractHandler{
    @Override
    void doFilter(Request request, Response response) {
        System.out.println("安全调用校验");
    }
}

连接对象数组

@Component("ChainPatternDemo")
public class ChainPatternDemo {
    //自动注入各个责任链的对象
    @Autowired
    private List<AbstractHandler> abstractHandleList;

    private AbstractHandler abstractHandler;
    @PostConstruct
    public void initializeChainFilter(){
        for (int  i = 0;i < abstractHandleList.size();i++ ){
            if (i == 0){
                abstractHandler = abstractHandleList.get(0);
            }else {
                AbstractHandler currentHander = abstractHandleList.get(i - 1);
                AbstractHandler nextHander = abstractHandleList.get(i);
                currentHander.setNextHandler(nextHander);
            }
        }
    }
    //直接调用这个方法使用
    public Response exec(Request request, Response response) {
        abstractHandler.filter(request, response);
        return response;
    }
    public AbstractHandler getAbstractHandler() {
        return abstractHandler;
    }
    public void setAbstractHandler(AbstractHandler abstractHandler) {
        this.abstractHandler = abstractHandler;
    }
}

模版方法模式

业务场景

一个请求都会经历几个相同的流程

定义

定义一个操作的一系列步骤,对于某些暂时确定不下来的步骤,就留给子类去实现,这样不同的子类就可以定义出不同的步骤。

使用
  • 一个抽象类,定义骨架流程(抽象方法放一起)
  • 确定的共同方法步骤,放到抽象类(去除抽象方法标记)
  • 不确定的步骤,给子类去差异化实现

观察者模式

业务场景

类似于触发器,一件事情的状态变化引发下一件事情。

定义

观察者模式属于行为模式,一个对象(被观察者)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。它的主要成员就是观察者和被观察者

使用
  • 一个被观察者的类Observerable ;
  • 多个观察者Observer ;
  • 观察者的差异化实现
  • 经典观察者模式封装:EventBus实战

EventBus实战

maven添加

            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>20.0</version>
                <scope>compile</scope>
            </dependency>

声明一个EventBusCenter类,类似于被观察者

public class EventBusCenter {
    private static EventBus eventBus = new EventBus();
    private EventBusCenter() {}
    public static EventBus getInstance() {
        return eventBus;
    }
    //添加观察者
    public static void register(Object obj) {
        eventBus.register(obj);
    }
    //移除观察者
    public static void unregister(Object obj) {
        eventBus.unregister(obj);
    }
    //把消息推给观察者
    public static void post(Object obj) {
        eventBus.post(obj);
    }
}

声明EventListener -观察者

public class EventListener {
    @Subscribe //加了订阅,这里标记这个方法是事件处理方法
    public void handle(NotifyEvent notifyEvent) {
        //触发的业务代码
    }
}

NotifyEvent - 通知时间

@Data
@AllArgsConstructor
@NoArgsConstructor
public class NotifyEvent {
    private String mobileNo;
    private String emailNo;
    private String imNo;
}

测试

public class EventBusDemoTest {
    public static void main(String[] args) {
        EventListener eventListener = new EventListener();
        EventBusCenter.register(eventListener);
        EventBusCenter.post(new NotifyEvent("13372817283", "123@qq.com", "666"));
       }
}

工厂模式

业务场景、定义

定义一个创建对象的接口,让子类决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

使用
  • 一个工厂接口,提供一个创建不同对象的方法。
  • 其子类实现工厂接口,构造不同对象
  • 使用工厂模式

单例模式

业务场景、定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

使用

饿汉模式:一开始把对象创建好,没有线程安全问题,但是会有内存浪费

public class EHanSingleton {
    private static EHanSingleton eHanSingleton = new EHanSingleton();
    private EHanSingleton(){};

    public static EHanSingleton geteHanSingleton(){
        return eHanSingleton;
    }
}

懒汉模式:要用的时候才创建对象,有线程问题,一般加上synchronized

public class LanHanSingleton {
    private static LanHanSingleton lanHanSingleton;
    private LanHanSingleton(){};

    public static synchronized LanHanSingleton getLanHanSingleton(){
        if (Optional.ofNullable(lanHanSingleton).isPresent()){
            lanHanSingleton = new LanHanSingleton();
        }
        return lanHanSingleton;
    }
}

双重校验锁:在synchronized关键字内外加一层if判断

public class DoubleCheckSingleton {
    private static DoubleCheckSingleton doubleCheckSingleton;
    private DoubleCheckSingleton(){}

    public static DoubleCheckSingleton getDoubleCheckSingleton(){
        if (Optional.ofNullable(doubleCheckSingleton).isPresent()){
            synchronized (DoubleCheckSingleton.class){
                doubleCheckSingleton = new DoubleCheckSingleton();
            }
        }
        return doubleCheckSingleton;
    }
}