zoukankan      html  css  js  c++  java
  • 应聘者页面——文本输入框及单选多视图重构

                 近期校招季。实习单位提供校招软件服务,线上用户比較多,并没有太多新功能上线,乐帝主要负责做一些重构的工作。想想今年毕业新来的同事,已经可以独立承担业务开发。乐帝近期对MVC架构有了更深的了解,编程能力也有一定的入门提高。从同事新胜那儿。学到非常多前端开发的规范,在这里再次感谢新胜耐心教导、无私帮助。

        乐帝与新胜最大的区别在于。新胜处理问题解决这个问题,都有深厚的理论功底,即知其所以然,而不单单是一个程序猿,他有自己的思考,懂得怎样优化代码与性能。乐帝向新胜学习他,构建的理论体系及解决这个问题的方法。高速缩小与新胜这个模范的差距。

        这篇文章所讨论视图,在单位。招聘项目里,应聘者功能下。那为什么须要重构呢?

        在这次重构工作中。我想有双方面原因:

    • 模板中处理逻辑过于复杂,不符合结构与处理逻辑分离,代码可读性不高。

    <select data-name="<%=Name%>" data-obj="<%=controlData.Object%>" class="souce_name search_view width130">
    		<option value="">不限</option>
    	<%if(typeof searchItems !="undefined"){%>
    		<%if(searchItems.Value!=null){%>
    		<%_.each(dataSource, function(item){%>
    		<%if(searchItems.Value.length>0){%>
    			<%_.each(searchItems.Value, function(item1){%>
    				
    				<%if(item1!=item.Value){%>
    				<option value="<%=item.Value%>"><%=item.Text%></option>
    				<%}else{%>
    				<option value="<%=item.Value%>" selected="selected"><%=item.Text%></option>
    				<%}%>
    			<%})%>
    		<%}else{%>
    		<option value="<%=item.Value%>"><%=item.Text%></option>
    		<%}%>	
    		<%})%>
    		<%}else{%>
    			<%_.each(dataSource, function(item){%>
    			<option value="<%=item.Value%>" title="<%=item.Text%>"><%=item.Text%></option>
    			<%})%>
    			<%}%>
    	<%}else{%>
    		<%_.each(dataSource, function(item){%>
    		<option value="<%=item.Value%>"><%=item.Text%></option>
    		<%})%>
    	<%}%>
    </select>

          如上所看到的,模板中用了多层if-else嵌套,夹杂各种<% %>以切割HTML和JS代码,结构与逻辑耦合度很高。可读性比較低。不利于改动。
    • 多个同类视图,在逻辑和结构上,仅仅有微小差异。但源码各写一套逻辑和视图,扩展性不高,造成大量代码冗余,不利于后期维护。
       乐帝做的第一步是将模板中逻辑提取出来,并将views.SearchItemView1、views.SearchItemView20、views.SearchItemView23,这三个视图模板採用Beyond Compare软件进行文字比对,发现三个模板差异,这里的差异包含两部分内容:结构差异与逻辑差异。当中结构上标签名都同样,仅仅是每一个视图部分标签属性值不同,这些属性值可在View中处理。

       乐帝最初的解决方式,是通过调试每一个视图传入model值。发现视图构建差异在model值中Ctype属性上。

      于是针对以上三个视图。针对Ctype推断,构建不同视图不同的属性值。

    textInputAttr:function(){
    				var isDefault = this.model.get("IsDefault");
    				var searchItems = this.model.get("searchItems");
    				var defaultVal  = this.model.get("DefaultVal");
    				var cType =this.model.get("Ctype");
    				if(cType==1){
    					this.$el.find("input[type='text']").addClass("search_box_prev");
    					this.$el.find("input[type='text']").attr("data-rule-maxlength",300);
    				}else{
    					this.$el.find("input[type='text']").addClass("souce_name");
    					this.$el.find("input[type='text']").attr("data-rule-maxlength",100);
    					if(cType==23){
    						this.$el.find("input[type='text']").addClass("default_word");
    					}
    				}//针对不同ctype设置input不同属性及值
    				if(cType==1){
    					if(typeof isDefault !="undefined"&&isDefault==1)
    					{
    						this.$el.find("input[type='text']").attr("defaultValue",defaultVal);
    					};// 设置defaultValue属性
    				}
    				
    				if(typeof searchItems !="undefined")
    				{
    					if(searchItems.Value!=null)
    					{
    						this.$el.find("input[type='text']").attr("value",searchItems.Value[0]);
    					}
    				}
    				else{
    					if(cType==1){
    						if(typeof isDefault !="undefined"&&isDefault==1){
    						this.$el.find("input[type='text']").attr("value",defaultVal);
    						}
    					}
    					
    				}//设置value属性值
    			},
    			checkInputAttr:function(){
    				var searchItems = this.model.get("searchItems");
    				var cType =this.model.get("Ctype");
    				if(cType==1){
    					this.$el.find("input[type='checkbox']").addClass("search_box_any");
    				}else{
    					this.$el.find("input[type='checkbox']").addClass("souce_name");
    				}
    					if((typeof searchItems !="undefined")&&(searchItems.Value!=null)&&(searchItems.Value.length>0)){
    							_.each(searchItems.Value,function(item,value){
    								var valLength = (cType==1)?

    (searchItems.Value.length):(searchItems.Value.length-1);//推断採用何种表达式 if(valLength==value){ if(item){ this.$el.find("input[type='checkbox']").attr("value",item); if(searchItems.Value[value]=="true") this.$el.find("input[type='checkbox']").attr("checked","checked"); }else{ this.$el.find("input[type='checkbox']").attr("value",""); } } }); }else{ this.$el.find("input[type='checkbox']").attr("value",""); } }//checkbox设置


                  这段代码存在的隐患是,依据Ctype做推断生成各视图,与model很相关,即与已有数据结构高度耦合。不利于扩展。假如在此逻辑上。我须要新加一个与上述三类视图同类的视图,那么还需在代码基础上。再次改进代码,增加对新视图Ctype推断,这显然不是我们想要的。

       重构真正的需求是:构造一个通用类,将每一个视图共通的地方写入此类中。在不同子视图中继承此通用类,如有差异可覆写通用类方法,实现个性化定制。
       有了如上思路,接下来做的工作,就是依据之前採用文本比对得出的差异部分,进行分块处理。即构造原子函数,确定都有哪些原子块。而且一并写到通用类中。差异的部分在原子类中以空方法形式存在。在子函数中覆写通用类空函数,实现个性化订制。
    var SingleInputView = Talent.ItemView.extend({
    			onBeforeRender:function(){
    				this.standLabel();//标准化标签
    			},
    			onRender:function(){
    				this.textMaxlen(this.maxlength);
    				this.setCheckboxVal(this.minus);
    				this.SetTextInput();
    				this.SetCheckboxInput();
    
    			},
    			standLabel:function(){
    				var label = this.model.get("Label");
    				if((label.length != 7)&&(label.length>6))
    				{
    					this.model.set({"Label":label.substring(0,6)+"…"});
    				}
    			},
    			textAddClass:function(){
    			},
    			textMaxlen:function(length){
    				this.$el.find("input[type='text']").attr("data-rule-maxlength",length);
    			},
    			setTextDefaultVal:function(){
    
    			},
    			setTextVal:function(){
    				var isDefault = this.model.get("IsDefault");
    				var searchItems = this.model.get("searchItems");
    				var defaultVal  = this.model.get("DefaultVal");
    				if(typeof searchItems !="undefined")
    				{
    					if(searchItems.Value!=null)
    					{
    						this.$el.find("input[type='text']").val(searchItems.Value[0]);
    					}
    				}
    			},
    			checkboxAddClass:function(){
    
    			},
    			setCheckboxVal:function(minus){
    				var searchItems = this.model.get("searchItems");
    				if((typeof searchItems !="undefined")&&(searchItems.Value!=null)&&(searchItems.Value.length>0)){
    							_.each(searchItems.Value,function(item,value){
    								var valLength =searchItems.Value.length-minus;//推断採用何种表达式
    								if(valLength==value){
    									if(item){
    										this.$el.find("input[type='checkbox']").val(item);
    										if(searchItems.Value[value]=="true")
    											this.$el.find("input[type='checkbox']").attr("checked","checked");
    									}else{
    										this.$el.find("input[type='checkbox']").val("");
    									}
    								}
    							});
    					}else{
    						this.$el.find("input[type='checkbox']").val("");
    					}
    			},
    		});

          有些逻辑代码,仅仅是随着视图不同,变量不同。这里在父类中,构造带变量的方法。并在子类中设置属性值。传入父类方法中,如:
    setCheckboxVal:function(minus){
    				var searchItems = this.model.get("searchItems");
    				if((typeof searchItems !="undefined")&&(searchItems.Value!=null)&&(searchItems.Value.length>0)){
    					_.each(searchItems.Value,function(item,value){
    						var valLength =searchItems.Value.length-minus;//推断採用何种表达式
    						if(valLength==value){
    							if(item){
    								this.$el.find("input[type='checkbox']").val(item);
    								if(searchItems.Value[value]=="true")
    									this.$el.find("input[type='checkbox']").attr("checked","checked");
    								}else{
    									this.$el.find("input[type='checkbox']").val("");
    								}
    							}
    					});

       在父类中构造了渲染后onRender回调函数,自己主动调用通用类及子视图方法:
    onRender:function(){
    				this.textMaxlen(this.maxlength);
    				this.setCheckboxVal(this.minus);
    				this.SetTextInput();
    				this.SetCheckboxInput();
    
    			}

                 这里用到两个this.SetTextInput()和this.SetCheckboxInput()两个方法,各自是在子类中实现,用以依照定制化需求,载入运行不同子类函数:
    SetTextInput:function(){
    				this.textAddClass();
    				this.setTextDefaultVal();
    				this.setTextVal();
    			}

            通用类,还用到一个onBeforeRender回调方法。用以在数据还没有渲染到模板时,对数据进行处理。
    onBeforeRender:function(){
    				this.standLabel();//标准化标签
    			}

        这样处理的优势在于,逻辑更清晰,而且充分利用此回调函数时序上的优势。
        通过对以上重构分析,我们能够得出重构的大体方向:
    • 对差异代码模块化,写入通用类的空方法中。
    • 仅仅有变量差异的代码,写入通用类中带參数方法中。
    • 最后调用方法,写在通用类中,并在子类中,构造定制化载入方法如SetTextInput方法的职能

  • 相关阅读:
    eclipse中设置自动生成的author,date等注释
    JSP基本指令
    java代码注释规范
    java中的 FileWriter类 和 FileReader类的一些基本用法
    关于java中BufferedReader的read()及readLine()方法的使用心得
    java开发中经典的三大框架SSH
    Java访问修饰符(访问控制符)
    Linux环境变量具体内容介绍
    MSG结构体和WndProc窗口过程详解
    Java当出现未被捕获的异常应该如何处理
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5183550.html
Copyright © 2011-2022 走看看