利用策略模式與退化的建造模式實現減少工作量的方法

前言

    大家都知道springMVC的使用,我們會少些很多servlet層面的代碼,但是隨着controller使用多了,就會我們的代碼上多出許多RequestMapping註解,

  舉個例子

    一個web文件管理的例子,用戶需要這個目錄的所有文件,請求到了一個RequestMapping方法,這時我們使用一個類來處理這個這個目錄下面的所有文件信息,

我們需要返回每個文件的詳細信息,這時如果使用RequestMapping方法就顯得有些雞肋了

  • 爲什麼呢?
  • 例如我們需要使用到很多RequestMapping方法來處理客戶端每個請求,你想啊,只是一個類似於ls的命令我們就需要創建一個往客戶端返回的json對象,當需要實現的功能很多時,這無疑是曾加了許多無用的勞動力,而且會讓我們創建很多json對象

好了問題出來了我們來找一個解決辦法,問題是什麼呢?

1、需要一個只需要實例化一次的json對象方法,2、儘量少些RequestMapping

 

下面我們先解決第二種問題

如果要少些RequestMapping方法就需要讓一個RequestMapping方法來解決客戶端的需求,這裏就要使用一個策略方法

具體實現方法如何實現呢

嗯,上代碼

例如

這個是它的一個接口

public interface CommandExecutorFactory {
    CommandExecutor get(String commName);

}

實現類

@Service("commandExecutorFactory")
public class DefaultCommandExecutorFactory  implements CommandExecutorFactory{


    String _classNamePattern;
    private Map<String,CommandExecutor>_map= new HashMap<String,CommandExecutor>();

    private CommandExecutor _fallbackCommand;
    
    @Override
    public CommandExecutor get(String commName) {
        
          if (_map.containsKey(commName)){
                return _map.get(commName);
            }
          try {
                String className = String.format(_classNamePattern,commName.
                        substring(0,1).toUpperCase()+commName.substring(1));
                return (CommandExecutor) Class.forName(className).newInstance();

            } catch (Exception e) {
                return _fallbackCommand;
            }
    }

    public String get_classNamePattern() {
        return _classNamePattern;
    }

    public void set_classNamePattern(String _classNamePattern) {
        this._classNamePattern = _classNamePattern;
    }

    public Map<String, CommandExecutor> get_map() {
        return _map;
    }

    public void set_map(Map<String, CommandExecutor> _map) {
        this._map = _map;
    }

    public CommandExecutor get_fallbackCommand() {
        return _fallbackCommand;
    }

    public void set_fallbackCommand(CommandExecutor _fallbackCommand) {
        this._fallbackCommand = _fallbackCommand;
    }

}

如何使用呢

public class CommandController{
    private CommandExecutorFactory commandExecutorFactory;

    private FsUserCommandFactory fsUserCommandFactory;
    
    

    public void connector(HttpServletRequest request,
             HttpServletResponse response)throws IOException, ServletException{
     CommandExecutor executor = null;
        
            executor = commandExecutorFactory.get(cmd);
    
        if(executor==null){
            throw new FsException(String.format("咱不不支持此方法: %s", cmd));
        }

。。。。。。。。。。。。。。
    }
}

 

通過配置的類的包路徑來通過class.forname轉換成對象文件,如果報錯的話說明是沒有此方法的我們返回到前端

這個是不是有點類似Struts的出來方式呢

第二個小問題解決了,這樣我們就只需要一個@requestMapping註解就可以

然後先說說第一個問題,如果僅僅只創建一個json對象很多人立刻想到,單例???

what。你在想什麼,也可能是我自己這樣想的把

其實springmvc這個在上層代碼結構裏爲我們解決了這個辦法,所使用的是建造模式的退化版本,相同於模板方法 ,這個退化版本又和模板方法差異’,

來看下UML

建造模式當退化的時候就變成了下列模樣

但是呢,還是推薦你去看原文《java與模式》建造模式一篇中詳細的介紹

貼張圖片

下面用一個比較簡單的方法來解決上面的問題

源碼是elfinder'的一個實現

我仿照了兩個它的兩個版本重新修改了下

地址https://github.com/glide-the/dmeck

先附代碼,之後詳細介紹

controller

@Controller
@RequestMapping("connector")
public class ConnectorController {

    @Resource(name = "commandExecutorFactory")
    private CommandExecutorFactory commandExecutorFactory;

    @Resource(name ="fsServiceFactory")
    private FsServiceFactory fsServiceFactory;

    @RequestMapping
    public void connector(HttpServletRequest request,
                          final HttpServletResponse response)throws IOException{
        /**
         * 文件上傳暫時不做
         */
        String cmd = request.getParameter("cmd");
        CommandExecutor executor = commandExecutorFactory.get(cmd);
        if(executor==null){
            throw new FsException(String.format("unknown command: %s", cmd));
        }

        try {
            final HttpServletRequest finalRequest = request;
                executor.execute(new CommandExectionContext() {
                    /**
                     * 總是返回一個factory
                     * @return
                     */
                    @Override
                    public FsServiceFactory getFsServiceFactory() {
                        return fsServiceFactory;
                    }

                    @Override
                    public HttpServletRequest getRequest() {
                        return finalRequest;
                    }

                    @Override
                    public HttpServletResponse getResponse() {
                        return response;
                    }

                    @Override
                    public ServletContext getServletContext() {
                    return finalRequest.getSession().getServletContext();
                }
                 });
        } catch (Exception e) {
            throw new FsException("unknown error", e);
        }

    }

。。。。。。。。。。

 

三個包裝接口

CommandExectionContext
public interface CommandExectionContext
{
    FsServiceFactory getFsServiceFactory();

    HttpServletRequest getRequest();

    HttpServletResponse getResponse();

    ServletContext getServletContext();
}
CommandExecutor
/**
 * 抽象工廠AbstractCommandExecutor的接口
 */
public interface CommandExecutor {
    void execute(CommandExectionContext commandExectionContext) throws  Exception;
}
CommandExecutorFactory
反射接口

public interface CommandExecutorFactory {
    CommandExecutor get (String commandName);
}
AbstractCommandExecutor
/**
 * 抽象工廠
 */
public abstract class AbstractCommandExecutor implements CommandExecutor {


    private static final String CMD_TMB_TARGET = "?cmd=tmb&target=%s";
    private Map<String, Object> map = new HashMap<>();

    @Override
    public void execute(CommandExectionContext ctx) throws Exception {
        FsService fileService = ctx.getFsServiceFactory().getFileService(ctx.getRequest(),ctx.getServletContext());

        execute(fileService,ctx.getRequest(),ctx.getResponse(),ctx.getServletContext());
    }

    public abstract void execute(FsService fileService, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext)throws  Exception;

-------------------------
AbstractorJsonCommandExecutor

/**
 * 抽象工廠裝飾類
 */
public abstract class AbstractorJsonCommandExecutor extends AbstractCommandExecutor {
    @Override
    final public void execute(FsService fsService, HttpServletRequest request, HttpServletResponse response,
                              ServletContext servletContext) throws Exception {

        JSONObject json = new JSONObject();

        try {
            execute(fsService, request, servletContext, json);
        } catch (ErrorException e) {
            /**
             * 自定義異常處理
             */
            if (e.getArgs() == null || e.getArgs().length == 0)
            {
                json.put("error", e.getError());
            } else
                {
                JSONArray errors = new JSONArray();
                errors.put(e.getError());
                for (String s : e.getArgs()) {
                    errors.put(s);
                }
                json.put("error", errors);
            }
        } catch (Exception e) {
            json.put("error", e.getMessage());
        } finally {
            response.setContentType("text/html;charset= UTF-8");

            PrintWriter writer = response.getWriter();
            json.write(writer);
            System.out.println(json);
            writer.flush();
            writer.close();
        }

    }

    protected abstract void execute(FsService fsService, HttpServletRequest request,
                                    ServletContext servletContext, JSONObject json) throws Exception;
}
DefaultCommandExecutorFactory
反射實現

public class DefaultCommandExecutorFactory implements CommandExecutorFactory {

    String _classNamePattern;

    private Map<String,CommandExecutor>_map= new HashMap<String,CommandExecutor>();

    private CommandExecutor _fallbackCommand;

    @Override
    public CommandExecutor get(String commandName) {

        if (_map.containsKey(commandName)){
            return _map.get(commandName);
        }

        try {
            String className = String.format(_classNamePattern,commandName.
                    substring(0,1).toUpperCase()+commandName.substring(1));
            return (CommandExecutor) Class.forName(className).newInstance();

        } catch (Exception e) {
            return _fallbackCommand;
        }

    }
OpenCommandExecutor

具體執行器
public class OpenCommandExecutor extends AbstractorJsonCommandExecutor
    implements CommandExecutor{
    @Override
    protected void execute(FsService fsService, HttpServletRequest request,
                           ServletContext servletContext, JSONObject json) throws Exception
    {
        boolean init = request.getParameter(ElFinderConstants.ELFINDER_PARAMETER_INIT) !=null;
        boolean tree = request.getParameter(ElFinderConstants.ELFINDER_PARAMETER_TREE) !=null;
        String target = request.getParameter(ElFinderConstants.ELFINDER_PARAMETER_TARGET);

        Map<String ,TargetEx> files= new LinkedHashMap<String, TargetEx>();
        if (init){
            json.put(ElFinderConstants.ELFINDER_PARAMETER_API,2.1);
            json.put(ElFinderConstants.ELFINDER_PARAMETER_NETDRIVERS,new Object[0]);
        }
        if (tree){
            for (Volume v : fsService.getVolumes()) {
                TargetEx root = new TargetEx(v.getRoot(), fsService);
                files.put(root.getHash(),root);
                addSubFolders(files,root);
            }
        }

        TargetEx cwd = finderCwd(fsService, target);
        files.put(cwd.getHash(),cwd);
        addChildren(files,cwd);

        json.put(ElFinderConstants.ELFINDER_PARAMETER_FILES,buildJsonFilesArray(request,files.values()));
        json.put(ElFinderConstants.ELFINDER_PARAMETER_CWD,getTargetInfo(request,cwd));
        json.put(ElFinderConstants.ELFINDER_PARAMETER_OPTIONS,getOptions(cwd));

    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章