代码之美

         好的代码,应该如何去定义? 

         我记得美国有过这样一个调查,从2014年到2015年一年时间里,他们询问了65名经验在5年以上的开发人员后,最终得出了这样一个结论:“好的代码是可读的,可理解的,覆盖了自动化测试的,不过于复杂,并且能办好我们需要它做的事情。”

        听起来很棒,Right?

        然而,应该如何把“他们”引入我们的项目中呢?而这一切的一切,我认为还要从,接口和抽象类说起。

        接口和抽象类有什么区别?为什么接口和抽象类不能实例化?为什么接口和抽象类必须由子类实现?

        因为计算机语言其实是人类思想的延伸,在机器的世界里,只需要子类就能完成具体逻辑,而接口和抽象类才是整个思维脉络的具体展现:接口是完成所需功能的具体执行步骤即顺序,而抽象类不仅是顺序还是相同类型的共享集合。

        我们以一个需求来举例:有一家工厂,因为市场需求,他们分别生产不同的小汽车:大、中、小。

        好了,让我们来编织思维,首先,抽象核心:产品和工厂,这里的抽象产品当然就是小汽车,子产品,就是:大中小三种汽车,抽象工厂当然也就是生产厂家,对应的也是大中小三汽车生产线。思维框架搭起来,我们就开始搭建软件框架。

        Test.Project

172442_Nrs5_2528735.gif           

        首先,搭起框架,不必急于编码,就算你明知有些子类可能为空,或者没有几行或者完全可以和别的类合并也一样。

        然后,开始编写内容。

        ICar.java

/**
 *  Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.interfaces;

/**
 * 汽车定制抽象产品接口
 *
 * @auther  kay
 * @since   1.0       	 
 */
public interface ICar {
	void getName();
}

         

        LowCar.java

/**
 *  Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.entity;

import com.kay.cn.interfaces.ICar;

/**
 * 低端汽车具体产品类
 *
 * @auther  kay
 * @since   1.0       	 
 */
public class LowCar implements ICar{
	public void getName() {
		System.out.println("LowCar");
	}
}

         

        MidCar.java

/**
 *  Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.entity;

import com.kay.cn.interfaces.ICar;

/**
 * 中端汽车具体产品类
 *
 * @auther  kay
 * @since   1.0       	 
 */
public class MidCar implements ICar{
	public void getName() {
		System.out.println("MidTop");
	}
}

         

        TopCar.java

/**
 *  Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.entity;

import com.kay.cn.interfaces.ICar;

/**
 * 高端汽车具体产品类
 *
 * @auther  kay
 * @since   1.0       	 
 */
public class TopCar implements ICar{
	public void getName() {
		System.out.println("TopCar");
	}
}

         

        AbstractFactory.java

/**
 *  Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.factory;

import com.kay.cn.interfaces.ICar;

/**
 * 抽象工厂
 *
 * @auther  kay
 * @since   1.0       	 
 */
public abstract class AbstractFactory {
	public abstract ICar create();
}

         

        LowFactory.java

/**
 * Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.entityfactory;

import com.kay.cn.entity.LowCar;
import com.kay.cn.factory.AbstractFactory;
import com.kay.cn.interfaces.ICar;

/**
 * 低档工厂
 *
 * @auther kay
 * @since 1.0
 */
public class LowFactory extends AbstractFactory {
	public ICar create() {
		return new LowCar();		//低档工厂生成低档小汽车对象
	}
}

         

        MidFactory.java

/**
 * Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.entityfactory;

import com.kay.cn.entity.MidCar;
import com.kay.cn.factory.AbstractFactory;
import com.kay.cn.interfaces.ICar;

/**
 * 中档工厂
 * 
 * @auther kay
 * @since 1.0
 */
public class MidFactory extends AbstractFactory {
	public ICar create() {
		return new MidCar();		//中档工厂生成中档小汽车对象
	}
}

         

        TopFactory.java

/**
 * Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.entityfactory;

import com.kay.cn.entity.TopCar;
import com.kay.cn.factory.AbstractFactory;
import com.kay.cn.interfaces.ICar;

/**
 * 高档工厂
 *
 * @auther kay
 * @since 1.0
 */
public class TopFactory extends AbstractFactory {
	public ICar create() {
		return new TopCar();		//高档工厂生成高档小汽车对象
	}
}

         

        Run.java

/**
 *  Copyright 2015 the original kay(1132892414@qq.com)
 */
package com.kay.cn.run;

import com.kay.cn.entityfactory.TopFactory;
import com.kay.cn.factory.AbstractFactory;
import com.kay.cn.interfaces.ICar;

/**
 * 测试类
 *
 * @auther  kay
 * @since   1.0       	 
 */
public class Run {
	public static void main(String[] args) {
		AbstractFactory obj = new TopFactory();
		ICar car = obj.create();
		car.getName();
	}
}

        这段代码最简单的语义描述就是“我们是小汽车工厂,生产并管理小汽车”。也就是说,抽象产品+抽象工厂定义好了,需要完成的工厂基本也就清晰了,就能马上转化为具体的代码实现。 

        其实,面向对象真正的魅力也正在于此。代码即思维,而思维源于生活。所以,我们编写的并不是软件,而是人们有了软件后,所能做的事,因为我相信无论是电脑还是软件,或是其他的什么,都是人类的一种延伸。人性是贪婪的,人们总是希望我们能从中获得更多,无论是对于工作、婚姻、金钱还是生活。这就是我们要做的,就是对于无限可能的信仰,化不可能为可能,你要让人们相信:无论你有怎样的梦想,你都可以通过他实现。

        所以,你所编写的东西,其真正的目的是为了打动别人、激发别人。所以谁会喜欢和一个丑陋的东西打交道呢?我所说的丑陋,不仅仅指UI而已,我们编写她应该不仅仅因为她能够做到我们所需要她做到的事,而且更应该充满艺术感,但没人在乎,这个世界错误的认为她应该非黑即白,但我们的生活,绘画和梦境都是彩色的,所以我认为她也应该是这样。

/*
 * Copyright 2002-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context;

import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.io.support.ResourcePatternResolver;

/**
 * Central interface to provide configuration for an application.
 * This is read-only while the application is running, but may be
 * reloaded if the implementation supports this.
 *
 * <p>An ApplicationContext provides:
 * <ul>
 * <li>Bean factory methods for accessing application components.
 * Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}.
 * <li>The ability to load file resources in a generic fashion.
 * Inherited from the {@link org.springframework.core.io.ResourceLoader} interface.
 * <li>The ability to publish events to registered listeners.
 * Inherited from the {@link ApplicationEventPublisher} interface.
 * <li>The ability to resolve messages, supporting internationalization.
 * Inherited from the {@link MessageSource} interface.
 * <li>Inheritance from a parent context. Definitions in a descendant context
 * will always take priority. This means, for example, that a single parent
 * context can be used by an entire web application, while each servlet has
 * its own child context that is independent of that of any other servlet.
 * </ul>
 *
 * <p>In addition to standard {@link org.springframework.beans.factory.BeanFactory}
 * lifecycle capabilities, ApplicationContext implementations detect and invoke
 * {@link ApplicationContextAware} beans as well as {@link ResourceLoaderAware},
 * {@link ApplicationEventPublisherAware} and {@link MessageSourceAware} beans.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see ConfigurableApplicationContext
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.core.io.ResourceLoader
 */
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

	/**
	 * Return the unique id of this application context.
	 * @return the unique id of the context, or {@code null} if none
	 */
	String getId();

	/**
	 * Return a name for the deployed application that this context belongs to.
	 * @return a name for the deployed application, or the empty String by default
	 */
	String getApplicationName();

	/**
	 * Return a friendly name for this context.
	 * @return a display name for this context (never {@code null})
	 */
	String getDisplayName();

	/**
	 * Return the timestamp when this context was first loaded.
	 * @return the timestamp (ms) when this context was first loaded
	 */
	long getStartupDate();

	/**
	 * Return the parent context, or {@code null} if there is no parent
	 * and this is the root of the context hierarchy.
	 * @return the parent context, or {@code null} if there is no parent
	 */
	ApplicationContext getParent();

	/**
	 * Expose AutowireCapableBeanFactory functionality for this context.
	 * <p>This is not typically used by application code, except for the purpose of
	 * initializing bean instances that live outside of the application context,
	 * applying the Spring bean lifecycle (fully or partly) to them.
	 * <p>Alternatively, the internal BeanFactory exposed by the
	 * {@link ConfigurableApplicationContext} interface offers access to the
	 * {@link AutowireCapableBeanFactory} interface too. The present method mainly
	 * serves as a convenient, specific facility on the ApplicationContext interface.
	 * <p><b>NOTE: As of 4.2, this method will consistently throw IllegalStateException
	 * after the application context has been closed.</b> In current Spring Framework
	 * versions, only refreshable application contexts behave that way; as of 4.2,
	 * all application context implementations will be required to comply.
	 * @return the AutowireCapableBeanFactory for this context
	 * @throws IllegalStateException if the context does not support the
	 * {@link AutowireCapableBeanFactory} interface, or does not hold an
	 * autowire-capable bean factory yet (e.g. if {@code refresh()} has
	 * never been called), or if the context has been closed already
	 * @see ConfigurableApplicationContext#refresh()
	 * @see ConfigurableApplicationContext#getBeanFactory()
	 */
	AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

         这是Spring源代码中随便找的一段代码,我想任何一个刚刚学会编程而且懂英文的人,都能大致的说出她的作用,而且就算给很资深的程序员也几乎没办法再继续做结构、功能、效率方面的简化了。这就是我们想要的效果。

         赏心悦目的代码,不仅仅可以很好体现易读性和易维护性,更会让人有兴趣去了解她。其实,这对一个成天和代码打交道的人来说是至关重要。所以,作为程序员的我们,应该尽我们一切的可能,去做到几个简单却至关重要的原则,以编写出好的代码:

         1)简洁

         我们的目的是编写出优雅简洁的代码。程序结构一定要清晰,并且简单易懂,单个函数的程序行数不应该超过100行。我个人认为做好的行数是30-50行,刚好一个屏幕,宽度不要超过100,过长的代码量不仅会影响大家理解,也会消耗架构的敏捷性。还要明确一个函数的目的性,所以其职责一定要单一。在实现时,一定要直接了当,代码精简,避免产生任何的垃圾代码。另外,尽量使用标准函数库和公共函数库。重复造轮子不仅浪费时间而且还不一定稳定。模块化的去编程,不仅是后台,还有前端。

         2)规范

         很多程序员不屑于编码规则,他们时常在项目中的变量或者常量简单的命名为aa、bb、cc。仅在这几行好像没什么大问题,但过个一年半载,天知道这是什么意思。还有不喜欢写注释,这是一个更不好的习惯。我们开发过程中,一定要非常严格的遵守编码规范。例如:1 .每个源程序文件都有头文件说明。2. 每个函数都有函数头说明。3. 定义或引用主要变量(结构、联合、类或对象)时,用注释反映含义。4. 常量定义要有相应的说明。5. 处理每个阶段都应该有相关的注释说明。6. 在典型算法前都有注释。等等。这对于经常要看代码的人来说,应该是深有感触的。

         3)高效

         提升性能的基本方法,1,不要再循环条件中计算。2,尽可能用final static。3,尽量缩小变量使用范围。4,学会使用StringBuilder等取代String。5,复写异常中fillInStackTrack方法。等等方法非常多。一般而言,没有慢的系统,只有架构不良的系统。使用好的架构,就不会有太多效率方面的问题,即使出现了也一般是二八原则,卡在了哪一个点,这时候需要程序员,深入思考,寻根探源。“病来如山倒,病去如抽丝”,系统优化也是相同的过程,一定不可急躁。

         4 ) 健壮

         一个比较模糊的概念,但却是非常重要的软件外部量度标准。简单来说,我们知道正确性是软件在需求之内的执行情况,而健壮性则是需求之外的执行情况。可以多使用异常,把性能问题放一边,而且我们提倡异常封装,因为一般Java API提供的异常都是比较低级的,只有开发人员才能看得懂具体发生了什么,而对于普通人来说,这简直是天书,合理的异常封装可以提高系统的友好度以及可维护性,也填补了Java异常处理机制的自身缺陷。但不建议finally里处理返回值以及在构造函数里抛出异常。

         5 ) 可扩展

         遵循经典的“开放-封闭”原则,而且心目中永远要有一个远大的目标,时刻做好准备。

         6)可靠

         避免发生故障的能力。还记得那个做Android刚满一个月就被老板踢断腿的人吗?

         7 ) 适应

         当今计算机环境复杂,浏览器产品也类型繁多。虽然这是外部原因,但我们必须要求他们在所有地方都能运行。

         8 ) 开源

         大胆的采用开源工具,MVC框架有struts,也有Spring MVC、WebWorker;Ioc 容器有Spring,也有Google Guice;ORM 既有Hibernate,也有MyBatis;日志记录有经典的log4j,也有崭新的logback。可选的很多,以至于无从选择。“大树底下好乘凉”在大树下,我们才有时间和精力纳凉,而不会把大量时间用于排查Bug上。而且同时,因为热度越高,Bug曝光率也越快,修复率也就越高,这对我们项目的稳定性来说非常重要。但很多开源项目可能已经很长没有更新或者濒临关闭了,我们不能要求太高,毕竟开源项目已经共享了他人的精力和智力,我们应该珍惜他人的劳动成果,最低标准,不要去诋毁。


         还有永远不要说,“如果时间允许我一定会写出更好的代码”,诸如此类的话。

         言外之意,就是如果时间不足我们就有放宽对代码质量的要求的权利了?

        我们应该在任何时刻都要保持精益求精,务求代码的正确无误,务求代码的清晰可读。一旦嗅到代码的“坏味道”,我们就应该及时重构。对于烂代码,我们就应该尽力去驯服!其次,心里一定要有一个想要去纠正的问题,而且他必须要能唤起你的激情,否则你必然没有毅力去把它完成。

        也永远不要说,不可能做的更快更好这样的话。而是要想,将会数千万人会用到你的东西。你自然而然就知道怎么做了。

        人生能做的事情没有几件,而现在我们选择了去做这个,那就应该把他做到最好。


        当你长大了,总有人对你说,这个世界有他的规则,你的人生也是在,这样的世界上度过的,别老是想着去打破规则。这样的人生太过狭隘,人生可以更加宽广,只要你能领悟一个简单的道理,那就是你身边的一切,所谓的生活,都是些不比你聪明的人,创造出来的。你能改变他,你可以影响他,你能自己创造出对别人有用的东西,一旦你跳出那个,“生活不可改变,只能去适应的荒谬观点”,转而拥抱它,改变它,升华它,给它烙上你的印记,一旦你明白这点,你的人生将从此不同。


——水门(2016年1月写于杭州)

转载于:https://my.oschina.net/kaywu123/blog/595507

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值