① 高内聚、低耦合的含义是什么如何提高代码的可重用性

网络粘过来的,你看看:
基本解释
高内聚低耦合,是软件工程中的概念,是判断设计好坏的标准,主要是面向对象的设计,主要是看类的内聚性是否高,耦合度是否低。
高内聚
内聚就是一个模块内各个元素彼此结合的紧密程度,高内聚就是一个模块内各个元素彼此结合的紧密程度高。 所谓高内聚是指一个软件模块是由相关性很强的代码组成,只负责一项任务,也就是常说的单一责任原则。
低耦合
耦合:一个软件结构内不同模块之间互连程度的度量(耦合性也叫块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差,模块间耦合的高低取决于模块间接口的复杂性,调用的方式以及传递的信息。) 对于低耦合,粗浅的理解是: 一个完整的系统,模块与模块之间,尽可能的使其独立存在。 也就是说,让每个模块,尽可能的独立完成某个特定的子功能。 模块与模块之间的接口,尽量的少而简单。 如果某两个模块间的关系比较复杂的话,最好首先考虑进一步的模块划分。 这样有利于修改和组合。[1]
编辑本段为什么要追求高内聚和低耦合
软件架构设计的目的简单说就是在保持软件内在联系的前提下,分解软件系统,降低软件系统开发的复杂性,而分解软件系统的基本方法无外乎分层和分割。但是在保持软件内在联系的前提下,如何分层分割系统,分层分割到什么样的粒度,并不是一件容易的事,这方面有各种各样的分解方法,比如:关注点分离,面向方面,面向对象,面向接口,面向服务,依赖注入,以及各种各样的设计原则等,而所有这些方法都基于高内聚,低耦合的原则。 高内聚和低耦合是相互矛盾的,分解粒度越粗的系统耦合性越低,分解粒度越细的系统内聚性越高,过度低耦合的软件系统,软件模块内部不可能高内聚,而过度高内聚的软件模块之间必然是高度依赖的,因此如何兼顾高内聚和低耦合是软件架构师功力的体现。 高内聚,低耦合的系统有什么好处呢?事实上,短期来看,并没有很明显的好处,甚至短期内会影响系统的开发进度,因为高内聚,低耦合的系统对开发设计人员提出了更高的要求。高内聚,低耦合的好处体现在系统持续发展的过程中,高内聚,低耦合的系统具有更好的重用性,维护性,扩展性,可以更高效的完成系统的维护开发,持续的支持业务的发展,而不会成为业务发展的障碍。[2]

② 面试中被问到了java中的“六原则一法则”是什么

原则包括:
单一职责原则:一个类只做它该做的事情。(单一职责原则想表达的就是”高内聚”,写代码最终极的原则只有六个字”高内聚、低耦合”,就如同葵花宝典或辟邪剑谱的中心思想就八个字”欲练此功必先自宫”,所谓的高内聚就是一个代码模块只完成一项功能,在面向对象中,如果只让一个类完成它该做的事,而不涉及与它无关的领域就是践行了高内聚的原则,这个类就只有单一职责。提醒大家有一句话叫”因为专注,所以专业”,一个对象如果承担太多的职责,那么注定它什么都做不好。这个世界上任何好的东西都有两个特征,一个是功能单一,好的相机绝对不是电视购物里面卖的那种一个机器有一百多种功能的,它基本上只能照相;另一个是模块化,好的自行车是组装车,从减震叉、刹车到变速器,所有的部件都是可以拆卸和重新组装的,好的乒乓球拍也不是成品拍,一定是底板和胶皮可以拆分和自行组装的,一个好的软件系统,它里面的每个功能模块也应该是可以轻易的拿到其他系统中使用的,这样才能实现软件复用的目标。)
开闭原则:软件实体应当对扩展开放,对修改关闭。(在理想的状态下,当我们需要为一个软件系统增加新功能时,只需要从原来的系统派生出一些新类就可以,不需要修改原来的任何一行代码。要做到开闭有两个要点:①抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点;②封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统将变得复杂而混乱,如果不清楚如何封装可变性,可以参考《设计模式精解》一书中对桥梁模式的讲解的章节。)

依赖倒转原则:面向接口编程。(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体类型,因为抽象类型可以被它的任何一个子类型所替代,请参考下面的里氏替换原则。)

里氏替换原则:任何时候都可以用子类型替换掉父类型。(关于里氏替换原则的描述,Barbara Liskov女士的描述比这个要复杂得多,但简单的说就是能用父类型的地方就一定能使用子类型。里氏替换原则可以检查继承关系是否合理,如果一个继承关系违背了里氏替换原则,那么这个继承关系一定是错误的,需要对代码进行重构。例如让猫继承狗,或者狗继承猫,又或者让正方形继承长方形都是错误的继承关系,因为你很容易找到违反里氏替换原则的场景。需要注意的是:子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多,把能力多的对象当成能力少的对象来用当然没有任何问题。
接口隔离原则:接口要小而专,绝不能大而全。(臃肿的接口是对接口的污染,既然接口表示能力,那么一个接口只应该描述一种能力,接口也应该是高度内聚的。例如,琴棋书画就应该分别设计为四个接口,而不应设计成一个接口中的四个方法,因为如果设计成一个接口中的四个方法,那么这个接口很难用,毕竟琴棋书画四样都精通的人还是少数,而如果设计成四个接口,会几项就实现几个接口,这样的话每个接口被复用的可能性是很高的。Java中的接口代表能力、代表约定、代表角色,能否正确的使用接口一定是编程水平高低的重要标识。)
合成聚合复用原则:
优先使用聚合或合成关系复用代码。(通过继承来复用代码是面向对象程序设计中被滥用得最多的东西,因为所有的教科书都无一例外的对继承进行了鼓吹从而误导了初学者,类与类之间简单的说有三种关系,Is-A关系、Has-A关系、Use-A关系,分别代表继承、关联和依赖。其中,关联关系根据其关联的强度又可以进一步划分为关联、聚合和合成,但说白了都是Has-A关系,合成聚合复用原则想表达的是优先考虑Has-A关系而不是Is-A关系复用代码,原因嘛可以自己从网络上找到一万个理由,浙江优就业需要说明的是,即使在Java的API中也有不少滥用继承的例子,例如Properties类继承了Hashtable类,Stack类继承了Vector类,这些继承明显就是错误的,更好的做法是在Properties类中放置一个Hashtable类型的成员并且将其键和值都设置为字符串来存储数据,而Stack类的设计也应该是在Stack类中放一个Vector对象来存储数据。记住:任何时候都不要继承工具类,工具是可以拥有并可以使用的,而不是拿来继承的。)
法则指迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。(迪米特法则简单的说就是如何做到”低耦合”,门面模式和调停者模式就是对迪米特法则的践行。对于门面模式可以举一个简单的例子,你去一家公司洽谈业务,你不需要了解这个公司内部是如何运作的,你甚至可以对这个公司一无所知,去的时候只需要找到公司入口处的前台美女,告诉她们你要做什么,她们会找到合适的人跟你接洽,前台的美女就是公司这个系统的门面。再复杂的系统都可以为用户提供一个简单的门面,Java Web开发中作为前端控制器的Servlet或Filter不就是一个门面吗,浏览器对服务器的运作方式一无所知,但是通过前端控制器就能够根据你的请求得到相应的服务。调停者模式也可以举一个简单的例子来说明,例如一台计算机,CPU、内存、硬盘、显卡、声卡各种设备需要相互配合才能很好的工作,但是如果这些东西都直接连接到一起,计算机的布线将异常复杂,在这种情况下,主板作为一个调停者的身份出现,它将各个设备连接在一起而不需要每个设备之间直接交换数据,这样就减小了系统的耦合度和复杂度)
这个问题在Java中属于比较基础的问题,但是也请题主不要灰心。面试是一个考量综合素质的过程,即使一两道题发挥不好也仍然拥有机会。

③ java怎么实现代码的可重用性

可重用性有很多方面
对象的重用
方法的重用
变量的重用
对象和变量的可重用性很好理解吧
对象就是类的可重用性的体现 把同一类型的对象抽象化 创建类
变量的重用在于 同一作用域 一次定义 到处使用
方法的可重用性 在于 把同一逻辑抽象出来作为方法 在作用域内反复使用
比如 做加法 3 +4 5+ 6 7+8 就是同一逻辑
抽象出方法 public static int add(int a ,int b){
return a+b;
}
现在只需要 int c = add(3,4) add(5,6)
次数少 逻辑简单看不出来什么 当逻辑复杂时 代码的可重用性 对于 代码的易读性是很好的提升

④ 1234567890可以组成哪些6位数,可重复使用

若可重复使用,可组成的6位数太多了,有
9×10×10×10×10×10=900000(个)

⑤ 6.mybatis里面的动态sql是怎么设定的,常用标签有那些以及其

1、动态SQL片段
通过SQL片段达到代码复用
<!-- 动态条件分页查询 -->
<sql id="sql_count">
select count(*)
</sql>
<sql id="sql_select">
select *
</sql>
<sql id="sql_where">
from icp
<dynamic prepend="where">
<isNotEmpty prepend="and" property="name">
name like '%$name$%'
</isNotEmpty>
<isNotEmpty prepend="and" property="path">
path like '%path$%'
</isNotEmpty>
<isNotEmpty prepend="and" property="area_id">
area_id = #area_id#
</isNotEmpty>
<isNotEmpty prepend="and" property="hided">
hided = #hided#
</isNotEmpty>
</dynamic>
<dynamic prepend="">
<isNotNull property="_start">
<isNotNull property="_size">
limit #_start#, #_size#
</isNotNull>
</isNotNull>
</dynamic>
</sql>
<select id="findByParamsForCount" parameterClass="map" resultClass="int">
<include refid="sql_count"/>
<include refid="sql_where"/>
</select>
<select id="findByParams" parameterClass="map" resultMap="icp.result_base">
<include refid="sql_select"/>
<include refid="sql_where"/>
</select>

2、数字范围查询
所传参数名称是捏造所得,非数据库字段,比如_img_size_ge、_img_size_lt字段
<isNotEmpty prepend="and" property="_img_size_ge">
<![CDATA[
img_size >= #_img_size_ge#
]]>
</isNotEmpty>
<isNotEmpty prepend="and" property="_img_size_lt">
<![CDATA[
img_size < #_img_size_lt#
]]>
</isNotEmpty>

多次使用一个参数也是允许的
<isNotEmpty prepend="and" property="_now">
<![CDATA[
execplantime >= #_now#
]]>
</isNotEmpty>
<isNotEmpty prepend="and" property="_now">
<![CDATA[
closeplantime <= #_now#
]]>
</isNotEmpty>

3、时间范围查询
<isNotEmpty prepend="" property="_starttime">
<isNotEmpty prepend="and" property="_endtime">
<![CDATA[
createtime >= #_starttime#
and createtime < #_endtime#
]]>
</isNotEmpty>
</isNotEmpty>

⑥ java 数组复用时 int A[]={2,6,7,9}; A = new int[2]; 后面的数组A是用的之前的空间还是另外的

另外的,只要是带 new 的,都会重新 分配 空间。

⑦ 如何提高代码质量6

高质量代码的三要素 我们评价高质量代码有三要素:可读性、可维护性、可变更性。我们的代码要一个都不能少地达到了这三要素的要求才能算高质量的代码。1.可读性强 一提到可读性似乎有一些老生常谈的味道,但令人沮丧的是,虽然大家一而再,再而三地强调可读性,但我们的代码在可读性方面依然做得非常糟糕。由于工作的需要,我常常需要去阅读他人的代码,维护他人设计的模块。每当我看到大段大段、密密麻麻的代码,而且还没有任何的注释时常常感慨不已,深深体会到了这项工作的重要。由于分工的需要,我们写的代码难免需要别人去阅读和维护的。而对于许多程序员来说,他们很少去阅读和维护别人的代码。正因为如此,他们很少关注代码的可读性,也对如何提高代码的可读性缺乏切身体会。有时即使为代码编写了注释,也常常是注释语言晦涩难懂形同天书,令阅读者反复斟酌依然不明其意。针对以上问题,我给大家以下建议:1)不要编写大段的代码 如果你有阅读他人代码的经验,当你看到别人写的大段大段的代码,而且还不怎么带注释,你是怎样的感觉,是不是“嗡”地一声头大。各种各样的功能纠缠在一个方法中,各种变量来回调用,相信任何人多不会认为它是高质量的代码,但却频繁地出现在我们编写的程序了。如果现在你再回顾自己写过的代码,你会发现,稍微编写一个复杂的功能,几百行的代码就出去了。一些比较好的办法就是分段。将大段的代码经过整理,分为功能相对独立的一段又一段,并且在每段的前端编写一段注释。这样的编写,比前面那些杂乱无章的大段代码确实进步了不少,但它们在功能独立性、可复用性、可维护性方面依然不尽人意。从另一个比较专业的评价标准来说,它没有实现低耦合、高内聚。我给大家的建议是,将这些相对独立的段落另外封装成一个又一个的函数。许多大师在自己的经典书籍中,都鼓励我们在编写代码的过程中应当养成不断重构的习惯。我们在编写代码的过程中常常要编写一些复杂的功能,起初是写在一个类的一个函数中。随着功能的逐渐展开,我们开始对复杂功能进行归纳整理,整理出了一个又一个的独立功能。这些独立功能有它与其它功能相互交流的输入输出数据。当我们分析到此处时,我们会非常自然地要将这些功能从原函数中分离出来,形成一个又一个独立的函数,供原函数调用。在编写这些函数时,我们应当仔细思考一下,为它们取一个释义名称,并为它们编写注释(后面还将详细讨论这个问题)。另一个需要思考的问题是,这些函数应当放到什么地方。这些函数可能放在原类中,也可能放到其它相应职责的类中,其遵循的原则应当是“职责驱动设计”(后面也将详细描述)。下面是我编写的一个从XML文件中读取数据,将其生成工厂的一个类。这个类最主要的一段程序就是初始化工厂,该功能归纳起来就是三部分功能:用各种方式尝试读取文件、以DOM的方式解析XML数据流、生成工厂。而这些功能被我归纳整理后封装在一个不同的函数中,并且为其取了释义名称和编写了注释:Java代码 /** * 初始化工厂。根据路径读取XML文件,将XML文件中的数据装载到工厂中 * @param path XML的路径 */ public void initFactory(String path){ if(findOnlyOneFileByClassPath(path)){return;} if(findResourcesByUrl(path)){return;} if(findResourcesByFile(path)){return;} this.paths = new String[]{path}; } /** * 初始化工厂。根据路径列表依次读取XML文件,将XML文件中的数据装载到工厂中 * @param paths 路径列表 */ public void initFactory(String[] paths){ for(int i=0; i<paths.length; i++){ initFactory(paths[i]); } this.paths = paths; } /** * 重新初始化工厂,初始化所需的参数,为上一次初始化工厂所用的参数。 */ public void reloadFactory(){ initFactory(this.paths); } /** * 采用ClassLoader的方式试图查找一个文件,并调用<code>readXmlStream()</code>进行解析 * @param path XML文件的路径 * @return 是否成功 */ protected boolean findOnlyOneFileByClassPath(String path){ boolean success = false; try { Resource resource = new ClassPathResource(path, this.getClass()); resource.setFilter(this.getFilter()); InputStream is = resource.getInputStream(); if(is==null){return false;} readXmlStream(is); success = true; } catch (SAXException e) { log.debug("Error when findOnlyOneFileByClassPath:"+path,e); } catch (IOException e) { log.debug("Error when findOnlyOneFileByClassPath:"+path,e); } catch (ParserConfigurationException e) { log.debug("Error when findOnlyOneFileByClassPath:"+path,e); } return success; } /** * 采用URL的方式试图查找一个目录中的所有XML文件,并调用<code>readXmlStream()</code>进行解析 * @param path XML文件的路径 * @return 是否成功 */ protected boolean findResourcesByUrl(String path){ boolean success = false; try { ResourcePath resourcePath = new PathMatchResource(path, this.getClass()); resourcePath.setFilter(this.getFilter()); Resource[] loaders = resourcePath.getResources(); for(int i=0; i<loaders.length; i++){ InputStream is = loaders[i].getInputStream(); if(is!=null){ readXmlStream(is); success = true; } } } catch (SAXException e) { log.debug("Error when findResourcesByUrl:"+path,e); } catch (IOException e) { log.debug("Error when findResourcesByUrl:"+path,e); } catch (ParserConfigurationException e) { log.debug("Error when findResourcesByUrl:"+path,e); } return success; } /** *用File的方式试图查找文件,并调用<code>readXmlStream()</code>解析 * @param path XML文件的路径 * @return 是否成功 */ protected boolean findResourcesByFile(String path){ boolean success = false; FileResource loader = new FileResource(new File(path)); loader.setFilter(this.getFilter()); try { Resource[] loaders = loader.getResources(); if(loaders==null){return false;} for(int i=0; i<loaders.length; i++){ InputStream is = loaders[i].getInputStream(); if(is!=null){ readXmlStream(is); success = true; } } } catch (IOException e) { log.debug("Error when findResourcesByFile:"+path,e); } catch (SAXException e) { log.debug("Error when findResourcesByFile:"+path,e); } catch (ParserConfigurationException e) { log.debug("Error when findResourcesByFile:"+path,e); } return success; } /** * 读取并解析一个XML的文件输入流,以Element的形式获取XML的根, * 然后调用<code>buildFactory(Element)</code>构建工厂 * @param inputStream 文件输入流 * @throws SAXException * @throws IOException * @throws ParserConfigurationException */ protected void readXmlStream(InputStream inputStream) throws SAXException, IOException, ParserConfigurationException{ if(inputStream==null){ throw new ParserConfigurationException("Cann't parse source because of InputStream is null!"); } DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(this.isValidating()); factory.setNamespaceAware(this.isNamespaceAware()); DocumentBuilder build = factory.newDocumentBuilder(); Document doc = build.parse(new InputSource(inputStream)); Element root = doc.getDocumentElement(); buildFactory(root); } /** * 用从一个XML的文件中读取的数据构建工厂 * @param root 从一个XML的文件中读取的数据的根 */ protected abstract void buildFactory(Element root); /** * 初始化工厂。根据路径读取XML文件,将XML文件中的数据装载到工厂中 * @param path XML的路径 */ public void initFactory(String path){ if(findOnlyOneFileByClassPath(path)){return;} if(findResourcesByUrl(path)){return;} if(findResourcesByFile(path)){return;} this.paths = new String[]{path}; } /** * 初始化工厂。根据路径列表依次读取XML文件,将XML文件中的数据装载到工厂中 * @param paths 路径列表 */ public void initFactory(String[] paths){ for(int i=0; i<paths.length; i++){ initFactory(paths[i]); } this.paths = paths; } /** * 重新初始化工厂,初始化所需的参数,为上一次初始化工厂所用的参数。 */ public void reloadFactory(){ initFactory(this.paths); } /** * 采用ClassLoader的方式试图查找一个文件,并调用<code>readXmlStream()</code>进行解析 * @param path XML文件的路径 * @return 是否成功 */ protected boolean findOnlyOneFileByClassPath(String path){ boolean success = false; try { Resource resource = new ClassPathResource(path, this.getClass()); resource.setFilter(this.getFilter()); InputStream is = resource.getInputStream(); if(is==null){return false;} readXmlStream(is); success = true; } catch (SAXException e) { log.debug("Error when findOnlyOneFileByClassPath:"+path,e); } catch (IOException e) { log.debug("Error when findOnlyOneFileByClassPath:"+path,e); } catch (ParserConfigurationException e) { log.debug("Error when findOnlyOneFileByClassPath:"+path,e); } return success; } /** * 采用URL的方式试图查找一个目录中的所有XML文件,并调用<code>readXmlStream()</code>进行解析 * @param path XML文件的路径 * @return 是否成功 */ protected boolean findResourcesByUrl(String path){ boolean success = false; try { ResourcePath resourcePath = new PathMatchResource(path, this.getClass()); resourcePath.setFilter(this.getFilter()); Resource[] loaders = resourcePath.getResources(); for(int i=0; i<loaders.length; i++){ InputStream is = loaders[i].getInputStream(); if(is!=null){ readXmlStream(is); success = true; } } } catch (SAXException e) { log.debug("Error when findResourcesByUrl:"+path,e); } catch (IOException e) { log.debug("Error when findResourcesByUrl:"+path,e); } catch (ParserConfigurationException e) { log.debug("Error when findResourcesByUrl:"+path,e); } return success; } /** * 用File的方式试图查找文件,并调用<code>readXmlStream()</code>解析 * @param path XML文件的路径 * @return 是否成功 */ protected boolean findResourcesByFile(String path){ boolean success = false; FileResource loader = new FileResource(new File(path)); loader.setFilter(this.getFilter()); try { Resource[] loaders = loader.getResources(); if(loaders==null){return false;} for(int i=0; i<loaders.length; i++){ InputStream is = loaders[i].getInputStream(); if(is!=null){ readXmlStream(is); success = true; } } } catch (IOException e) { log.debug("Error when findResourcesByFile:"+path,e); } catch (SAXException e) { log.debug("Error when findResourcesByFile:"+path,e); } catch (ParserConfigurationException e) { log.debug("Error when findResourcesByFile:"+path,e); } return success; } /** * 读取并解析一个XML的文件输入流,以Element的形式获取XML的根, * 然后调用<code>buildFactory(Element)</code>构建工厂 * @param inputStream 文件输入流 * @throws SAXException * @throws IOException * @throws ParserConfigurationException */ protected void readXmlStream(InputStream inputStream) throws SAXException, IOException, ParserConfigurationException{ if(inputStream==null){ throw new ParserConfigurationException("Cann't parse source because of InputStream is null!"); } DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(this.isValidating()); factory.setNamespaceAware(this.isNamespaceAware()); DocumentBuilder build = factory.newDocumentBuilder(); Document doc = build.parse(new InputSource(inputStream)); Element root = doc.getDocumentElement(); buildFactory(root); } /** * 用从一个XML的文件中读取的数据构建工厂 * @param root 从一个XML的文件中读取的数据的根 */ protected abstract void buildFactory(Element root); 完整代码在附件中。在编写代码的过程中,通常有两种不同的方式。一种是从下往上编写,也就是按照顺序,每分出去一个函数,都要将这个函数编写完,才回到主程序,继续往下编写。而一些更有经验的程序员会采用另外一种从上往下的编写方式。当他们在编写程序的时候,每个被分出去的程序,可以暂时只写一个空程序而不去具体实现功能。当主程序完成以后,再一个个实现它的所有子程序。采用这样的编写方式,可以使复杂程序有更好的规划,避免只见树木不见森林的弊病。有多少代码就算大段代码,每个人有自己的理解。我编写代码,每当达到15~20行的时候,我就开始考虑是否需要重构代码。同理,一个类也不应当有太多的函数,当函数达到一定程度的时候就应该考虑分为多个类了;一个包也不应当有太多的类。。。。。。2)释义名称与注释 我们在命名变量、函数、属性、类以及包的时候,应当仔细想想,使名称更加符合相应的功能。我们常常在说,设计一个系统时应当有一个或多个系统分析师对整个系统的包、类以及相关的函数和属性进行规划,但在通常的项目中这都非常难于做到。对它们的命名更多的还是程序员来完成。但是,在一个项目开始的时候,应当对项目的命名出台一个规范。譬如,在我的项目中规定,新增记录用new或add开头,更新记录用edit或mod开头,删除用del开头,查询用find或query开头。使用最乱的就是get,因此我规定,get开头的函数仅仅用于获取类属性。注释是每个项目组都在不断强调的,可是依然有许多的代码没有任何的注释。为什么呢?因为每个项目在开发过程中往往时间都是非常紧的。在紧张的代码开发过程中,注释往往就渐渐地被忽略了。利用开发工具的代码编写模板也许可以解决这个问题。用我们常用的MyEclipse为例,在菜单“window>>Preferences>>Java>>Code Style>>Code Templates>>Comments”中,可以简单的修改一下。“Files”代表的是我们每新建一个文件(可能是类也可能是接口)时编写的注释,我通常设定为:Java代码 /* * created on ${date} */ /* * created on ${date} */“Types”代表的是我们新建的接口或类前的注释,我通常设定为:Java代码 /** * * @author ${user} */ /** * * @author ${user} */第一行为一个空行,是用于你写该类的注释。如果你采用“职责驱动设计”,这里首先应当描述的是该类的职责。如果需要,你可以写该类一些重要的方法及其用法、该类的属性及其中文含义等。${user}代表的是你在windows中登陆的用户名。如果这个用户名不是你的名称,你可以直接写死为你自己的名称。其它我通常都保持为默认值。通过以上设定,你在创建类或接口的时候,系统将自动为你编写好注释,然后你可以在这个基础上进行修改,大大提高注释编写的效率。同时,如果你在代码中新增了一个函数时,通过Alt+Shift+J快捷键,可以按照模板快速添加注释。在编写代码时如果你编写的是一个接口或抽象类,我还建议你在@author后面增加@see注释,将该接口或抽象类的所有实现类列出来,因为阅读者在阅读的时候,寻找接口或抽象类的实现类比较困难。Java代码 /** * 抽象的单表数组查询实现类,仅用于单表查询 * @author 范钢 * @see com.htxx.support.query.DefaultArrayQuery * @see com.htxx.support.query.DwrQuery */ public abstract class ArrayQuery implements ISingleQuery { ... /** * 抽象的单表数组查询实现类,仅用于单表查询 * @author 范钢 * @see com.htxx.support.query.DefaultArrayQuery * @see com.htxx.support.query.DwrQuery */public abstract class ArrayQuery implements ISingleQuery {...2.可维护性 软件的可维护性有几层意思,首先的意思就是能够适应软件在部署和使用中的各种情况。从这个角度上来说,它对我们的软件提出的要求就是不能将代码写死。1)代码不能写死 我曾经见我的同事将系统要读取的一个日志文件指定在C盘的一个固定目录下,如果系统部署时没有这个目录以及这个文件就会出错。如果他将这个决定路径下的目录改为相对路径,或者通过一个属性文件可以修改,代码岂不就写活了。一般来说,我在设计中需要使用日志文件、属性文件、配置文件,通常都是以下几个方式:将文件放到与类相同的目录,使用ClassLoader.getResource()来读取;将文件放到classpath目录下,用File的相对路径来读取;使用web.xml或另一个属性文件来制定读取路径。我也曾见另一家公司的软件要求,在部署的时候必须在C:/bea目录下,如果换成其它目录则不能正常运行。这样的设定常常为软件部署时带来许多的麻烦。如果服务器在该目录下已经没有多余空间,或者已经有其它软件,将是很挠头的事情。2)预测可能发生的变化 除此之外,在设计的时候,如果将一些关键参数放到配置文件中,可以为软件部署和使用带来更多的灵活性。要做到这一点,要求我们在软件设计时,应当更多地有更多的意识,考虑到软件应用中可能发生的变化。比如,有一次我在设计财务软件的时候,考虑到一些单据在制作时的前置条件,在不同企业使用的时候,可能要求不一样,有些企业可能要求严格些而有些要求松散些。考虑到这种可能的变化,我将前置条件设计为可配置的,就可能方便部署人员在实际部署中进行灵活变化。然而这样的配置,必要的注释说明是非常必要的。软件的可维护性的另一层意思就是软件的设计便于日后的变更。这一层意思与软件的可变更性是重合的。所有的软件设计理论的发展,都是从软件的可变更性这一要求逐渐展开的,它成为了软件设计理论的核心。3.可变更性 前面我提到了,软件的变更性是所有软件理论的核心,那么什么是软件的可变更性呢?按照现在的软件理论,客户对软件的需求时时刻刻在发生着变化。当软件设计好以后,为应对客户需求的变更而进行的代码修改,其所需要付出的代价,就是软件设计的可变更性。由于软件合理地设计,修改所付出的代价越小,则软件的可变更性越好,即代码设计的质量越高。一种非常理想的状态是,无论客户需求怎样变化,软件只需进行适当地修改就能够适应。但这之所以称之为理想状态,因为客户需求变化是有大有小的。如果客户需求变化非常大,即使再好的设计也无法应付,甚至重新开发。然而,客户需求的适当变化,一个合理地设计可以使得变更代价最小化,延续我们设计的软件的生命力。1)通过提高代码复用提高可维护性 我曾经遇到过这样一件事,我要维护的一个系统因为应用范围的扩大,它对机关级次的计算方式需要改变一种策略。如果这个项目统一采用一段公用方法来计算机关级次,这样一个修改实在太简单了,就是修改这个公用方法即可。但是,事实却不一样,对机关级次计算的代码遍布整个项目,甚至有些还写入到了那些复杂的SQL语句中。在这样一种情况下,这样一个需求的修改无异于需要遍历这个项目代码。这样一个实例显示了一个项目代码复用的重要,然而不幸的是,代码无法很好复用的情况遍布我们所有的项目。代码复用的道理十分简单,但要具体运作起来非常复杂,它除了需要很好的代码规划,还需要持续地代码重构。对整个系统的整体分析与合理规划可以根本地保证代码复用。系统分析师通过用例模型、领域模型、分析模型的一步一步分析,最后通过正向工程,生成系统需要设计的各种类及其各自的属性和方法。采用这种方法,功能被合理地划分到这个类中,可以很好地保证代码复用。采用以上方法虽然好,但技术难度较高,需要有高深的系统分析师,并不是所有项目都能普遍采用的,特别是时间比较紧张的项目。通过开发人员在设计过程中的重构,也许更加实用。当某个开发人员在开发一段代码时,发现该功能与前面已经开发功能相同,或者部分相同。这时,这个开发人员可以对前面已经开发的功能进行重构,将可以通用的代码提取出来,进行相应地改造,使其具有一定的通用性,便于各个地方可以使用。一些比较成功的项目组会指定一个专门管理通用代码的人,负责收集和整理项目组中各个成员编写的,可以通用的代码。这个负责人同时也应当具有一定的代码编写功力,因为将专用代码提升为通用代码,或者以前使用该通用代码的某个功能,由于业务变更,而对这个通用代码的变更要求,都对这个负责人提出了很高的能力要求。虽然后一种方式非常实用,但是它有些亡羊补牢的味道,不能从整体上对项目代码进行有效规划。正因为两种方法各有利弊,因此在项目中应当配合使用。2)利用设计模式提高可变更性 对于初学者,软件设计理论常常感觉晦涩难懂。一个快速提高软件质量的捷径就是利用设计模式。这里说的设计模式,不仅仅指经典的32个模式,是一切前人总结的,我们可以利用的、更加广泛的设计模式。a. if...else...这个我也不知道叫什么名字,最早是哪位大师总结的,它出现在Larman的《UML与模式应用》,也出现在出现在Mardin的《敏捷软件开发》。它是这样描述的:当你发现你必须要设计这样的代码:“if...elseif...elseif...else...”时,你应当想到你的代码应当重构一下了。我们先看看这样的代码有怎样的特点。Java代码 if(var.equals("A")){ doA(); }else if(var.equals("B")){ doB(); }else if(var.equals("C")){ doC(); }else{ doD(); } if(var.equals("A")){ doA(); }else if(var.equals("B")){ doB(); }else if(var.equals("C")){ doC(); }else{ doD(); }这样的代码很常见,也非常平常,我们大家都写过。但正是这样平常才隐藏着我们永远没有注意的问题。问题就在于,如果某一天这个选项不再仅仅是A、B、C,而是增加了新的选项,会怎样呢?你也许会说,那没有关系,我把代码改改就行。然而事实上并非如此,在大型软件研发与维护中有一个原则,每次的变更尽量不要去修改原有的代码。如果我们重构一下,能保证不修改原有代码,仅仅增加新的代码就能应付选项的增加,这就增加了这段代码的可维护性和可变更性,提高了代码质量。那么,我们应当如何去做呢?经过深入分析你会发现,这里存在一个对应关系,即A对应doA(),B对应doB()...如果将doA()、doB()、doC()...与原有代码解耦,问题就解决了。如何解耦呢?设计一个接口X以及它的实现A、B、C...每个类都包含一个方法doX(),并且将doA()的代码放到A.doX()中,将doB()的代码放到B.doX()中...经过以上的重构,代码还是这些代码,效果却完全不一样了。我们只需要这样写:Java代码 X x = factory.getBean(var); x.doX(); X x = factory.getBean(var);x.doX();这样就可以实现以上的功能了。我们看到这里有一个工厂,放着所有的A、B、C...并且与它们的key对应起来,并且写在配置文件中。如果出现新的选项时,通过修改配置文件就可以无限制的增加下去。这个模式虽然有效提高了代码质量,但是不能滥用,并非只要出现if...else...就需要使用。由于它使用了工厂,一定程度上增加了代码复杂度,因此仅仅在选项较多,并且增加选项的可能性很大的情况下才可以使用。另外,要使用这个模式,继承我在附件中提供的抽象类XmlBuildFactoryFacade就可以快速建立一个工厂。如果你的项目放在spring或其它可配置框架中,也可以快速建立工厂。设计一个Map静态属性并使其V为这些A、B、C...这个工厂就建立起来了。b.策略模式 也许你看过策略模式(strategy model)的相关资料但没有留下太多的印象。一个简单的例子可以让你快速理解它。如果一个员工系统中,员工被分为临时工和正式工并且在不同的地方相应的行为不一样。在设计它们的时候,你肯定设计一个抽象的员工类,并且设计两个继承类:临时工和正式工。这样,通过下塑类型,可以在不同的地方表现出临时工和正式工的各自行为。在另一个系统中,员工被分为了销售人员、技术人员、管理人员并且也在不同的地方相应的行为不一样。同样,我们在设计时也是设计一个抽象的员工类,并且设计数个继承类:销售人员、技术人员、管理人员。现在,我们要把这两个系统合并起来,也就是说,在新的系统中,员工既被分为临时工和正式工,又被分为了销售人员、技术人员、管理人员,这时候如何设计。如果我们还是使用以往的设计,我们将不得不设计很多继承类:销售临时工、销售正式工、技术临时工、技术正式工...如此的设计,在随着划分的类型,以及每种类型的选项的增多,呈笛卡尔增长。通过以上一个系

⑧ 频分复用的6. 优点


频率复用系统的最大优点是信道复用率高,允许复用的路数多,同时它的分路也很方便。因此,它是目前模拟通信中最主要的一种复用方式,特别是在有线、微波通信系统及卫星通信系统内广泛应用。例如,在卫星通信系统中的频分多址(FDMA)方式,就是按照频率的不同,把各地球站发射的信号安排在卫星频带内的指定位置进行频分复用,然后,按照频率不同来区分地球站站址,进行多址复用。
· 有效减少多径及频率选择性信道造成接收端误码率上升的影响;
· 接收端可利用简单一阶均衡器补偿信道传输的失真;
· 频谱效率上升。

⑨ 代码重用性很重要吗怎样在自己的代码中重用他人的优秀代码如何去得到这些代码

看你要做什么、为什么人做了。如果你的公司把代码行数当KPI的话,听我的,千万别想着什么代码重用。甚至循环、递归神马的,能不用就尽量别用。如果一个功能,比如排序,如果计算机执行它需要O(n log n)条指令,咱最好就写出这么多行代码——简单省心,而且KPI源源而来。偶曾经在某外包公司,为这种公司写了个线程调度器,可以把任何耗时的调用变成异步,不需要改原本的处理逻辑和接口(这就意味着要自动维护参数传递所用的内存,一个小操作系统的雏形)。这个东东我就用了150来行C代码(加上注释300多行),高效、安全、可靠,0bug。很得意。然后就被批评代码行数太少——这玩意儿要当个操作系统来写,几百万行都打不住;再用上我之前说的“不循环不递归,全部一条条手工咔咔代码”这个小手段,光这个功能飙上数千万行代码简直太轻松不过了。哪怕一条代码1毛钱,这就直接创造了几百万的价值。结果被我这个笨蛋300行就搞定了,导致公司承受了数百万的惨重损失^_^。前车之鉴啊。____________________________但,如果你们是写真正到市场上公平竞争的软件——这种公司绝对不会用代码行数当KPI指标——那么,你就必须时刻琢磨着,哪段代码可以重用。代码的可重用性之所以重要,并不仅仅是说今后类似项目可以挖来用;而是在当前项目中,你的一些基础算法实现本身就可以当作库来用,可以作为高层算法所操作的基本原子。比如说,你要统计教授、助教、领导以及食堂工人的工资,那么就必须考虑到,所有的工资都是工资,都可以用同样的方式来统计。在这个案例里,能否重用工资统计算法,代码量就是5、6倍的差异;这5、6倍的代码理所当然会带来5、6倍的bug——甚至,因为你必须区分不同的人群来选择不同的统计算法,这个选择算法本身也会带来额外的bug。最终,你可能要多写10倍的代码,多出10倍的bug,并最终导致你的软件比竞争对手晚一年才能上市。反之,如果你会说,工资统计说白了也是统计;所有的统计都是一样的——那好,现在你的系统里,不仅无需区分教授、助教,甚至可以无需区分采购、维护、拨款等等不同项目:因为说到底,它们都是把一些数字加起来,然后算平均算方差算总额……如此而已。一旦你能想到这步,那么你就可以用原来几十分之一的代码,完成所有功能。代码量少、逻辑简单,自然bug就少;同时,应当需求变更的能力也就更强。于是,当竞争对手的软件需要半年才能上市时,你可能一个星期就已经搞定了。而且,由于简单,你的东西可以一写出来就是0bug;而对手,却要被用户的投诉搞的焦头烂额。代码重用之所以重要,这就是原因。——————————————————————另外,对商业公司来说,请 不要抄袭他人的优秀代码 。甚至看的半懂不懂,然后把其中的看懂的一部分改头换面,用自己的方式敲出来,都是不行的——而且,这也并 不是重用, 还会惹上极为麻烦的法律问题——当然,国内的话,无视这点吧。前面已经说过,重用最重要的,是重用自己的代码,这样才可能利用重用来减少代码量、简化程序结构、提高生产效率。这和抄袭优秀代码,本质上是不同的。而且,优秀代码有自己的适用范围。离开了这个特定的适用范围,它很可能就充满了bug。我做过一个项目,最初的实验论证阶段要做一个粗糙实现。其中的网络通信部分,我先写了一部分;写完有人提议,说可以用openvpn的。想想也对,反正这个版本只是论证,肯定不拿出去卖,直接利用成熟的代码应该能节省点时间。于是剩下的一部分就直接调用openvpn里的通信函数了。写完测试,却发现无法工作。花了几个小时调试,最后跟进去才发现,我写的代码完全正常,但到了openvpn代码那里就停住不动了。这才发现,虽然做的是几乎完全相同的工作,但由于openvpn自己的特殊需要额外做了一个动作,这个动作就导致程序不能正常工作。把来自openvpn的代码全部删掉,替换成我的东西,也就十几分钟的功夫,程序很顺利就跑起来了。