需求:查询年龄大于20岁的用户
查询工资大于5000的用户
准备一个用户实体类
@Data
@AllArgsConstructor
@ToString
public class User {
private String name;
private int age;
private double salary;
}
测试类
@SpringBootTest
class PracticeApplicationTests {
//准备一个操作的集合模拟查询数据库
private List<User> users = Arrays.asList(
new User("张三",12,4000),
new User("李四",42,3000),
new User("王五",32,5000),
new User("赵六",22,6000),
new User("陈七",52,8000),
);
//查询年龄大于20的用户
public List<User> getUserByAge(List<User> list){
List<User> users = new LinkedList<User>();
for (User user : list) {
if (user.getAge > 20){
users.add(user);
}
}
return users;
}
//查询工资大于5000的用户
public List<User> getUserBySalary(List<User> list){
List<User> users = new LinkedList<User>();
for (User user : list) {
if (user.getSalary > 5000){
users.add(user);
}
}
return users;
}
//调用这两个方法查看结果
@Test
public void testStrategy(){
List<User> userByAge = getUserByAge(users);
for (User user : userByAge) {
System.out.println(user);
}
System.out.println("-------------分割线---------------");
List<User> userBySalary = getUserBySalary(users);
for (User user : userBySalary) {
System.out.println(user);
}
}
}
打印结果如下
User(name=李四, age=42, salary=3000.0)
User(name=王五, age=32, salary=5000.0)
User(name=赵六, age=22, salary=6000.0)
-------------分割线---------------
User(name=赵六, age=22, salary=6000.0)
通过观察我们发现上面两个方法只有if( )
中的语句不同,其他的完全相同,那么有什么办法优化一下?我们添加一个接口,接口定义行为,我们在接口中定义的行为就是一个方法test,通过test方法来实现对User的过滤功能。再增加两个实现,一个是按照年龄过滤,一个是按照工资过滤
public interface StrategyFilter {
public boolean test(User u);
}
public class StrategyUserAgeFilter implements StrategyFilter{
@Override
public boolean test(User user) {
return user.getAge() > 20;
}
}
public class StrategyUserSalaryFilter implements StrategyFilter{
@Override
public boolean test(User user) {
return user.getSalary() > 5000;
}
}
最终我们的代码是这样
public List<User> userFilter(List<User> list,StrategyFilter filter){
List<User> users = new LinkedList<User>();
for (User u : list) {
if (filter.test(u)){
users.add(u);
}
}
return users;
}
@Test
public void testStrategy(){
List<User> userByAge = userFilter(users, new StrategyUserAgeFilter());
for (User user : userByAge) {
System.out.println(user);
}
List<User> userBySalary = userFilter(users, new StrategyUserSalaryFilter());
for (User user : userBySalary ) {
System.out.println(user);
}
}
最终结果
User(name=李四, age=42, salary=3000.0)
User(name=王五, age=32, salary=5000.0)
User(name=赵六, age=22, salary=6000.0)
-------------分割线---------------
User(name=赵六, age=22, salary=6000.0)
上面这就基本上是一个简单的策略模式了,根据需要不同选择不同的策略,这个时候又来了一个需求,说有一个X类,要求通过其中的某个属性过滤,这个时候怎么办呢?其实通过上面的代码我们就基本上已经很清楚了,增加一个泛型即可,因此最终我们的方法变成了下面这样
// 声明一个泛型接口,定义核心方法过滤
public interface StrategyFilter<T> {
public boolean test(T t);
}
//用户年龄的过滤实现
public class StrategyUserAgeFilter implements StrategyFilter<User>{
@Override
public boolean test(User user) {
return user.getAge() > 20;
}
}
@Data
@AllArgsConstructor
@ToString
public class People {
@ApiModelProperty("肤色")
private String skinColour;
@ApiModelProperty("体格")
private Integer physique;
}
//人类肤色的过滤实现
public class StrategyPeopleFilter implements StrategyFilter<People> {
@Override
public boolean test(People people) {
return "黄".equals(people.getSkinColour());
}
}
等等各种各样的实现都可以自己定义
最终我们调用方法如下
private List<People> peoples = Arrays.asList(
new People("黄",12),
new People("白",22),
new People("黑",23)
);
public <T> List<T> beanFilter(List<T> list,StrategyFilter<T> filter){
List<T> ts= new LinkedList<T>();
for (T t : list) {
if (filter.test(t)){
users.add(t);
}
}
return ts;
}
@Test
public void testStrategy(){
List<User> userByAge = beanFilter(users, new StrategyUserAgeFilter());
for (User user : userByAge) {
System.out.println(user);
}
System.out.println("-------------分割线---------------");
List<User> userBySalary = beanFilter(users, new StrategyUserSalaryFilter());
for (User user : userBySalary) {
System.out.println(user);
}
for (People people : beanFilter(peoples, new StrategyPeopleFilter())) {
System.out.println(people);
}
//这样我们每个扩展都要实现接口重写方法,因此也可以用匿名内部类的方式来实现
List<Dept> depts = beanFilter(Arrays.asList(
new Dept("财务部"),
new Dept("研发部"),
new Dept("行政部")
), new StrategyFilter<Dept>() {
@Override
public boolean test(Dept dept) {
return "财务部".equals(dept.getName());
}
});
}
最终结果
User(name=李四, age=42, salary=3000.0)
User(name=王五, age=32, salary=5000.0)
User(name=赵六, age=22, salary=6000.0)
-------------分割线---------------
User(name=赵六, age=22, salary=6000.0)
People(skinColour=黄, physique=12)
我们看到用匿名内部类的时候还是有些内容例如 new StrategyFilter()
那么可以用java8的lambda表达式来简化
@Test
public void testStrategy(){
List<User> userByAge = beanFilter(users, new StrategyUserAgeFilter());
for (User user : userByAge) {
System.out.println(user);
}
System.out.println("-------------分割线---------------");
List<User> userBySalary = beanFilter(users, new StrategyUserSalaryFilter());
for (User user : userBySalary) {
System.out.println(user);
}
for (People people : beanFilter(peoples, new StrategyPeopleFilter())) {
System.out.println(people);
}
//这样我们每个扩展都要实现接口重写方法,因此也可以用匿名内部类的方式来实现
List<Dept> depts = beanFilter(Arrays.asList(
new Dept("财务部"),
new Dept("研发部"),
new Dept("行政部")
), new StrategyFilter<Dept>() {
@Override
public boolean test(Dept dept) {
return "财务部".equals(dept.getName());
}
});
//lambda 表达式
List<Dept> depts1 = beanFilter(Arrays.asList(
new Dept("财务部"),
new Dept("研发部"),
new Dept("行政部")
),(dept) -> "财务部".equals(dept.getName()));
}