复习中看到设计模式中的策略模式,于是想到了之前一个项目要调出含有视频的文章,又要调出含有图片的文章,略符合使用策略模式,于是想先试用一下。
策略模式
主要是用于让子类去实现不同的算法或者操作,在之后根据情况来调用用的最多的就是不同的打折情况
一个简单的策略模式的实现:
/* 策略对象 */
public interface Strategy {
void Method();
.....
/*具体的策略实现*/
public class AStrategy implements Strategy{
@Override
public void Method() {
System.out.println("我是A方法");
}
}
public class BStrategy implements Strategy{
@Override
public void Method() {
System.out.println("俺不一样");
System.out.println("我是A的爸爸,B");
}
}
public class CStrategy implements Strategy{
@Override
public void Method() {
System.out.println("我是C,犬子无礼还望多多海涵");
}
}
...
/*创造策略*/
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy=strategy;
}
public void OneMethod(){
strategy.Method();
}
}
...
/*main方法中调用*/
public class StrategyTest {
public static void main(String[] args) {
Context context = new Context(new AStrategy());
context.OneMethod();
}
}
这种模式适用于方法产生变化,如新增一种实现方法,改变实现方法中的某些操作等等,还有一个对象有很多行为,使用if-else就显得杂乱且后期难以维护。而我说的查找文章略微符合的原因就在这里,因为我只有两种选择,后期应该也不怎么会增加新的类别文章了(就只有视频,图片,纯文本啊,这还能有第4种???),
工厂模式
上面的策略模式避开了if-else,但是我们是自己来new实现类的,感觉不是很稳妥
Context context = new Context(new AStrategy());
那我要使用B或者C那不是又回到使用if-else判断里面了?
所以这个时候就要用到工厂模式了:
创建型的设计模式,它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。
这个博主举了个比较详细的例子策略模式vs工厂模式的区别
工厂模式:有一天你决定去吃KFC,一看菜单,哦,种类很多呀,你就点了个老北京,过了二十分钟,你的老北京就来了就可以吃到了。但这个老北京是怎么做的,到底面粉放了多少,鸡肉放了多少,佐料放了多少,有多少到工序,你是不需要管的,你需要的是一个美味老北京。
而这个老北京怎么做呢,由策略模式决定
策略模式:同样还是在KFC,你要一个老北京,老板说想吃自己去做吧。原料有鸡肉、面粉、佐料。工序有1、2、3工序,你自己去做吧。然后你就需要自己按照策略去做,到底放多少培根,放多少面粉,放多少佐料,这都你自己来决定,工序1、2、3,你是怎么实现的,都你自己决定。最后你得到了老北京。
很显然工厂模式 + 策略模式 = 我告诉你名字,你就自己去找相应的方法去实现然后给我呈上来
Spring Boot的实现
首先来看看原本的实现
/*Controller层*/
public JSONObject getAllCheckedArticle(@RequestParam("pageNum") String pageNum,@RequestParam("row") String row,@RequestParam("type") int type){
return articleService.getCheckedArticle(Integer.parseInt(pageNum),Integer.parseInt(row),type);
}
/*实现层*/
public JSONObject getCheckedArticle(int pageNum, int rows,int type) {
PageHelper.startPage(pageNum, rows);
List<Article> articles = articleMapper.getCheckedArticle(type);//直接从数据库筛选
.....
}
写道这里发现我没怎么用if-else啊!,不对,剧本不对重新来
/*实现层*/
public JSONObject getCheckedArticle(int pageNum, int rows,int type) {
if(1==type){
List<Article> articles = articleMapper.getCheckedArticleByMediaType("video")
}else if(2==type){
List<Article> articles = articleMapper.getCheckedArticleByMediaType("image")
}else{
List<Article> articles = articleMapper.getCheckedArticleByMediaType("null")
}
.....
}
好了这才是正常剧本,前面因为直接优化数据库的结构就能做到一行筛选所以效果不是那么明显。
Service层
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;
/**
* @Author: xc
* @Date: 2019/10/24 19:53
* @Description: 获得文章的策略接口
**/
@Service
public interface GetArticleStrategy {
/**
* 获得文章策略接口
* @param type
* 1.Image
* 2.Video
* @return
*/
JSONObject getArticle(String type);
}
Impl层
package com.example.strage_test.service.Impl;
import com.alibaba.fastjson.JSONObject;
import com.example.strage_test.service.GetArticleStrategy;
import org.springframework.stereotype.Component;
/**
* @Author: xc
* @Date: 2019/10/24 20:02
* @Description:
**/
@Component("Video")
public class GetArticleWithVideo implements GetArticleStrategy {
@Override
public JSONObject getArticle(String type) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg","包含视频的文章");
return jsonObject;
}
}
package com.example.strage_test.service.Impl;
import com.alibaba.fastjson.JSONObject;
import com.example.strage_test.service.GetArticleStrategy;
import org.springframework.stereotype.Component;
/**
* @Author: xc
* @Date: 2019/10/24 19:57
* @Description:
**/
@Component("Image")
public class GetArticleWithImage implements GetArticleStrategy {
@Override
public JSONObject getArticle(String type) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg","包含图片的文章");
return jsonObject;
}
}
Context
package com.example.strage_test.context;
import com.alibaba.fastjson.JSONObject;
import com.example.strage_test.service.GetArticleStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author: xc
* @Date: 2019/10/24 20:31
* @Description:
**/
@Service
public class GetArticleStrategyContext {
@Autowired
private final Map<String, GetArticleStrategy> strategyMap = new ConcurrentHashMap<>();
/**
* 工厂模式将实现了GetArticleStrategy的Bean注入Context中
* @param strategyMap
*/
public GetArticleStrategyContext(Map<String, GetArticleStrategy> strategyMap) {
this.strategyMap.clear();
strategyMap.forEach((k,v)->strategyMap.put(k,v));
}
public JSONObject getArticle(String type){
return strategyMap.get(type).getArticle(type);
}
}
因为只是测试,真正的调用并没有写在Controller层之中,而是写在测试类里
@Autowired
GetArticleStrategyContext context;
@Test
public void Test(){
JSONObject jsonObject = context.getArticle("Video");
JSONObject jsonObject2 = context.getArticle("Image");
System.out.println(jsonObject);
System.out.println(jsonObject2);
}
测试截图
这样就可以根据前端发送的请求参数选择相应的策略啦