策略模式
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:主要解决接口选择的问题。
如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。
关键代码:创建过程在其子类执行。
需求
我们在系统开发的过程中一定遇到过前端传递时间,那么此时产品经理想要在页面上通过一个下拉列表的形式选择不同的时间类型,然后在做业务处理的时候可以使用不同的时间。 例如下图:
每个选择项都是一个时间区间,下面我们通过前端传入类型数字,后端代码来实现。
1、创建日期类型枚举类接收前端传入的数字
/**
* 日期类型枚举类
**/
@Getter
public enum DaytypeEnum {
TODAY(0, "今天"),
FIRST_DAY_OF_WEEK(1, "本周"),
FIRST_DAY_OF_MONTH(2, "本月"),
FIRST_DAY_OF_LAST_MONTH(3, "上月"),
FIRST_DAY_OF_QUARTER(4, "本季度"),
FIRST_DAY_OF_YEAR(5, "本年"),
FIRST_DAY_OF_LAST_YEAR(6, "上年"),
OTHER(10,"其他"),
ALL(999,"全部")
;
private String message;
private Integer code;
DaytypeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
2、创建获取日期区间接口
/**
* 获取日期区间接口
**/
public interface ISectionDate {
SectionDateVo getDate(LocalDate date);
}
/**
* 日期区间
**/
@Data
public class SectionDateVo {
private String startDate;
private String endDate;
}
3、创建不同的策略者的实现方法
/**
* 今天的时期区间
**/
public class TodayStrategy implements ISectionDate {
@Override
public SectionDateVo getDate(LocalDate date) {
String today = String.valueOf(date);
return SectionDateVo.builder().startDate(today + DateFactory.START_TIME)
.endDate(today + DateFactory.START_TIME).build();
}
}
/**
* 当期日期本周的第一天到当前日期的区间
**/
public class FirstDayOfWeekStrategy implements ISectionDate {
@Override
public SectionDateVo getDate(LocalDate date) {
String firstDayOfWeek = String.valueOf(date.with(DayOfWeek.MONDAY));
String today = String.valueOf(date);
return SectionDateVo.builder().startDate(firstDayOfWeek + DateFactory.START_TIME)
.endDate(today + DateFactory.END_TIME).build();
}
}
/**
* 当前日期的本月的第一天到当前日期的时间区间
**/
public class FirstDayOfMonthStrategy implements ISectionDate {
@Override
public SectionDateVo getDate(LocalDate date) {
String firstDayOfMonth = String.valueOf(date.with(TemporalAdjusters.firstDayOfMonth()));
String today = String.valueOf(date);
return SectionDateVo.builder().startDate(firstDayOfMonth + DateFactory.START_TIME)
.endDate(today + DateFactory.END_TIME).build();
}
}
/**
* 当前日期的上月的第一天到上月的最后一天的时间区间
**/
public class FirstDayOfLastMonthStrategy implements ISectionDate {
@Override
public SectionDateVo getDate(LocalDate date) {
String firstDayOfMonth = String.valueOf(date.minusMonths(1L).with(TemporalAdjusters.firstDayOfMonth()));
String lastDayOfMonth = String.valueOf(date.minusMonths(1L).with(TemporalAdjusters.lastDayOfMonth()));
return SectionDateVo.builder().startDate(firstDayOfMonth + DateFactory.START_TIME)
.endDate(lastDayOfMonth + DateFactory.END_TIME).build();
}
}
/**
* 当前季度的季初和季末的时间区间
**/
public class FirstDayOfQuarterStrategy implements ISectionDate {
@Override
public SectionDateVo getDate(LocalDate date) {
TemporalQuery<LocalDate> querterOfYearQuery1 = new TemporalQuery<LocalDate>() {
@Override
public LocalDate queryFrom(TemporalAccessor temporal) {
LocalDate now = LocalDate.from(temporal);
if (now.isBefore(now.with(Month.APRIL).withDayOfMonth(1))) {
return now.with(Month.JANUARY).withDayOfMonth(1);
} else if (now.isBefore(now.with(Month.JULY).withDayOfMonth(1))) {
return now.with(Month.APRIL).withDayOfMonth(1);
} else if (now.isBefore(now.with(Month.OCTOBER).withDayOfMonth(1))) {
return now.with(Month.JULY).withDayOfMonth(1);
} else {
return now.with(Month.OCTOBER).withDayOfMonth(1);
}
}
};
TemporalQuery<LocalDate> querterOfYearQuery2 = new TemporalQuery<LocalDate>() {
@Override
public LocalDate queryFrom(TemporalAccessor temporal) {
LocalDate now = LocalDate.from(temporal);
if (now.isBefore(now.with(Month.APRIL).withDayOfMonth(1))) {
return now.with(Month.MARCH).with(TemporalAdjusters.lastDayOfMonth());
} else if (now.isBefore(now.with(Month.JULY).withDayOfMonth(1))) {
return now.with(Month.JUNE).with(TemporalAdjusters.lastDayOfMonth());
} else if (now.isBefore(now.with(Month.OCTOBER).withDayOfMonth(1))) {
return now.with(Month.SEPTEMBER).with(TemporalAdjusters.lastDayOfMonth());
} else {
return now.with(Month.DECEMBER).with(TemporalAdjusters.lastDayOfMonth());
}
}
};
String firstDayOfQuarter = String.valueOf(date.query(querterOfYearQuery1));
String lastDayOfQuarter = String.valueOf(date.query(querterOfYearQuery2));
return SectionDateVo.builder()
.startDate(firstDayOfQuarter + DateFactory.START_TIME)
.endDate(lastDayOfQuarter + DateFactory.END_TIME).build();
}
}
/**
* 当前日期的本年第一天到当前日期的区间
**/
public class FirstDayOfYearStrategy implements ISectionDate {
@Override
public SectionDateVo getDate(LocalDate date) {
String firstDayOfYear = String.valueOf(date.with(TemporalAdjusters.firstDayOfYear()));
String today = String.valueOf(date);
return SectionDateVo.builder()
.startDate(firstDayOfYear + DateFactory.START_TIME)
.endDate(today + DateFactory.END_TIME).build();
}
}
/**
* 当前的日期的前一年的第一天到前一年的最后一天的时间区间
**/
public class FirstDayOfLastYearStrategy implements ISectionDate {
@Override
public SectionDateVo getDate(LocalDate date) {
String firstDayOfYear = String.valueOf(date.minusYears(1L).with(TemporalAdjusters.firstDayOfYear()));
String lastDayOfYear = String.valueOf(date.minusYears(1L).with(TemporalAdjusters.lastDayOfYear()));
return SectionDateVo.builder()
.startDate(firstDayOfYear + DateFactory.START_TIME)
.endDate(lastDayOfYear + DateFactory.END_TIME).build();
}
}
4、创建工厂方法
/**
* 获取日期区间的工厂方法
**/
public class DateFactory {
private DateFactory() {
}
public static final String START_TIME = " 00:00:00";
public static final String END_TIME = " 23:59:59";
private static Map<Integer, ISectionDate> registerMap = new HashMap<>();
static {
registerMap.put(DaytypeEnum.TODAY.getCode(), new TodayStrategy());
registerMap.put(DaytypeEnum.FIRST_DAY_OF_WEEK.getCode(), new FirstDayOfWeekStrategy());
registerMap.put(DaytypeEnum.FIRST_DAY_OF_MONTH.getCode(), new FirstDayOfMonthStrategy());
registerMap.put(DaytypeEnum.FIRST_DAY_OF_LAST_MONTH.getCode(), new FirstDayOfLastMonthStrategy());
registerMap.put(DaytypeEnum.FIRST_DAY_OF_QUARTER.getCode(), new FirstDayOfQuarterStrategy());
registerMap.put(DaytypeEnum.FIRST_DAY_OF_YEAR.getCode(), new FirstDayOfYearStrategy());
registerMap.put(DaytypeEnum.FIRST_DAY_OF_LAST_YEAR.getCode(), new FirstDayOfLastYearStrategy());
registerMap.put(DaytypeEnum.ALL.getCode(), new EmpTySectionDate());
}
private static final ISectionDate EMPTY = new EmpTySectionDate();
private static class EmpTySectionDate implements ISectionDate {
@Override
public SectionDateVo getDate(LocalDate date) {
return new SectionDateVo();
}
}
private static ISectionDate getStrategist(Integer state) {
ISectionDate strategist = registerMap.get(state);
return strategist == null ? EMPTY : strategist;
}
public static SectionDateVo getDate(Integer state) {
ISectionDate strategist = getStrategist(state);
return strategist.getDate(LocalDate.now());
}
}