[转载]窃以为软件的最大追求是在合适的地方做正确的事

窃以为软件的最大追求是在合适的地方做正确的事
前段时间读了《软件的最大追求是什么》,击节叫好,深以为然,虽然该文章很多地方显得有点极端。

如今的软件系统越来越复杂,如果软件的结构不好会影响软件的可维护性,重构代码是一件极其痛苦的事情。

关于软件的复杂性问题,我做了一些思考:

1) Cyclomatic Complexity (圈复杂性 = number of decision points +1
   其中number of decision points是指一个if else之类的条件判断语句
(引自《软件的最大追求是什么》)

if else 语句可以被行为模式/策略模式代替,不妨看下列的例子:

假设我们要根据条件判断来完成不同的行为,用if else 是这样写的:

main(){
if(case A){
//do with strategy A
}else(case B){
//do with strategy B
}else(case C){
//do with strategy C
}
}


用策略模式则如下:
class runner{
do();
}

class A extends runner{
do(){
//do with strategy A
}
}

class B extends runner{
do(){
//do with strategy B
}
}

class A extends runner{
do(){
//do with strategy C
}
}

main(){
runner.do();
}
用了策略模式后main()中的语句的确简单多了,再也看不到该死的if else了^_^酷~~~

可实际上是这样简单吗???仔细研究一下上面的代码就能看出问题出来,首先这两段代码中的A、B、C的实际意义是不一样的:第一段代码中ABC代表的是某 一个逻辑条件的值而第二段中的ABC则是具体的类;第二段得到如此简化的前提是它得到的逻辑条件就是一个类;如果得到的仍然只是一个逻辑条件,那么为了达 到代码简化的效果,必须由另一个类(或方法)完成这种逻辑条件到具体类的转换,会出现类似下列的代码
class RunnerFactory{
runner getInstante(case){
if (case A) return new A();
else if (case B) return new B();
else if (case C) return new C();
}
}
从测试的角度来说,两者的测试分支都是3,复杂度相同,而第二种方法在很多的时候貌似还要测试借口的有效性。用策略模式还有一个缺点就是会使系统中的类的 数量大大的增加,如上的例子,采用if else类的数量为1,而采用策略模式的类个数为5个或6个(主要取决于逻辑映射是否用单独的类)。

如果逻辑判断的条件有三个,每个逻辑条件有三种可能的话,用策略模式系统至少会增加10个新类;如果条件更多的话类的个数也会更多

这么看来GOF的策略模式还要它干嘛??

当然不是,策略模式在很多情况下是一种非常好的解决方案。

这还要从if else 语句造成程序复杂以至难以维护的真正原因说起。就我个人的感觉真正造成if else语句难以维护的原因是每一个逻辑分支中的处 理语句过长。比如我现在工作中维护的代码,常常一个条件下面的业务处理语句有两三千行,每次我光确定某个逻辑分支的结束位置就要找半天,头晕-_-!。如 果是多层条件的话情况就更糟了。一个分支就一千多行,几个分支上万行自然很难维护。

if else 语句本质上是程序的流程控制语句,而分支中N长的代码通常是业务处理语句。行为模式/策略模式就是把流程判断和业务处理进行了一次解耦,将业务逻辑封装成 一个个单独的类。换句话说,行为模式/策略模式并不是不需要if else 语句(事实上该判断的还是要判断),只不过的换了地方或者是别的代码帮你做 了。另一方面,进行逻辑判断的语句被集中起来而不是分散在程序的各个角落,有利于逻辑本身的维护。策略模式/行为模式还有一个明显的好处就是如果新增加了 一种状态,我们只需要新增加一个策略类(同上的ABC)就可以了,避免了在程序中改动那些大段大段让人厌烦的if else 语句。

所以对于你的程序来说到底是使用设计模式还是简单的使用if else 关键在于你的程序是否复杂,有没有必要将控制逻辑和业务逻辑进行解耦。当然如果你可以用别的方式实现解耦也是非常好的。

2) Response for Class(RFC)
当一个类和很多其他类存在依赖时,它就变得复杂甚至难以修改和维护,这样,RFC值越大,表示你的系统味道越坏。(引自《软件的最大追求是什么》)

复杂性是由类与类之间的依赖关系(dependency)造成的。具体如下所示:

interface Runner;

class A implement runner{
do(){};
}

一个大型的系统中很多地方用到了runner接口,于是在很多地方出现了如下的相同代码:

{
Runner r = new A();
r.do();
}
如果因为某种原因runner接口的实现类改为B,则在所有用到runner接口的地方代码都要统统改为:
{
//Runner r = new A();
Runner r = new B();
r.do();
}
这些遍布系统各个角落的改动是繁琐且容易出错的。于是出现了各种框架和模式,其中最著名的当然是IOC(Inversion of Control)反转控制或者称之为依赖型注射(Dependency Injection)
那些讨厌的代码变成了如下:
{
ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");
Runner r = (Runner)ctx.getBean("Runner");
r.do();
}
这样我们就不需要对各个角落的代码进行维护了,容器会自动的为我们选择合适的类。

我到觉得维护的工作还是我们的,为了让容器注射入合适的类,我们必须要维护一个叫spring.xml的配置文件,或者如果你不喜欢配置文件这个东东的话 (比如偶)就得自己写一个注册类,将依赖关系一一注册进去。你还要为使用该接口的类定义一个以该接口为参数的构造函数或者该接口的setter方法,好让 容器可以将实现类顺利的注射进来。

该做的还是要做,只不过换了一个地方做而已。但就是换了个地方,实现了对依赖关系的集中维护(又是集中),大大的改善了系统的结构,明确了不同职责单位之间的分工。呵呵,有时自己也极端的觉得设计的工作说到底就是解决代码结构的问题^_^

IOC一直是和轻量级框架联系在一起的。所谓的重量级框架EJB也有实现相同功能的解决方案:Service Locator

Service Locator就是一个定位器,它维护了一个数据结构(比如一个表),通过这个定位器你可以准确的定位到你的接口想要的实现类,Service Locator同样使你免去了改变接口实现类后的维护恶梦:
{
Runner r = (Runner)ServiceLocator.lookup("Runner");
r.do();
}

无论是IOC还是Service Locator都帮助你维护了类之间的依赖关系。那么是否我们在编程中一定要用呢,这又是个权衡的问题,IOC带来了很 多的好处,不过我个人认为它的代码是让人费解的(你根本不知道它做了什么),并且为了用它,一方面你要借助于容器,另一方面你要编写配置文件,要为依赖型 注射提供合适的途径。

如果你的系统类之间的依赖型错综复杂,需求的变化常常导致实现类的变化,同时你又希望采用测试驱动的快速开 发模式,IOC毫无疑问是一个完美的解决方案;如果你的系统不存在上述的问题,为什么不简简单单的在程序中写死呢,何苦去维护一堆配置文件(我所在的开发 部门貌似都比较痛恨配置文件这个东东)。Service Locator也有很多缺点,被骂的最多的就是没法快速测试。

反转控制,即转换控制权。依赖关系控制权的转换是对代码结构的一次重构,重构的目标还是解耦,让不同的职责代码集中放到不同的地方,于是程序员可以更加专注的解决特定的问题,比如业务逻辑。

程序设计的发展就是对代码结构的不断调整,不断解耦,让特定的代码解决特定的问题而不是什么都混在一起。从面向过程到面向对象难道不是这样吗,封装的本质也是解耦。

在实际问题的解决当中,最重要的信条就是合适,要记住任何结构的改进都会付出代价,你的改进是否值得你为此付出的代价。比如当你做一个嵌入式程序的时候你 首要考虑的自然是效率问题;而如果你做的是一个ERP产品,在系统设计的时候,光系统的可维护性问题就让你不得不绞尽脑汁考虑一下代码的结构。

一句话,只做最对的。

程序设计的最大追求就是在合适的地方做正确的事。

语句不通顺,愿博会心一笑。欢迎交流:shenzhipeng1983@gmail.com

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-132298/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/374079/viewspace-132298/

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
【6层】4837.9平米六层框架综合办公楼(含计算书、建筑、结构图纸) 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值