• 如何开发一个扩展性高、维护性好的软件系统?(一个程序员最基本的修养)


    在这里插入图片描述

    我们要解决什么问题?

    以下是我们在实际工作中常常会遇到的问题。搞明白了以下的问题,此文就算学会了。掌握了此文的知识,你的代码水平也将提高一个台阶。

    1 实际工作中看到同事写的代码是不是很抓狂?别人看到你的代码是否会抓狂?
    2 有没有发现看不懂自己曾经写的代码?
    3 有没有发现随着功能的增加,一个方法里的代码越写越多,代码冗长?
    4 有没有发现,需求变更时,代码就像动手术,要大改?
    5 有没有发现,需求变更时,别的功能以前好好的功能,突然不能用了?

    这里没谈什么多牛的东西,也谈不上架构,以下内容是做为一个程序员最基本的修养。

    注释

    这没什么好争论的,必须要写注释。每个方法头、属性、具体功能、关键算法等,都请写上注释。关键的算法或功能,比如库存扣减、佣金等功能,请写上具体逻辑注释。

    有人可能会反驳,认为不需要写注释,理由是:有表达力的代码是无需注释的。但你要注意,每个同事的水平都不一样。你写完的代码,别人能快速看懂吗?只有写上我们的母语注释,才能做到快速get代码对应的意义。

    命名

    一个项目里,请使用统一的命名方式,并且具有可读性。
    统一命名方式:指的是,所有人都遵守同一套命名方式。别各写各的。具体用什么方式,团队自行决定,网上有很多。
    可读性:建议用英文单词命名,下划线分隔或驼峰式。不建议用拼音、拼音简写、aaa bbb纯字母等。
    推荐写法:string companyName = “腾讯控股”
    不推荐写法:string cn = “腾讯控股”、或 sting tengxun = “腾讯控股”、或 string aaa = “腾讯控股”

    单一职责

    注意了,这是重点,很重要很重要,在很多很多企业里,都有人写出一大坨一大坨的代码,让别人很痛苦,影响产品的生命力。

    什么是单一职责?一个类只有一个功能,一个方法只有一个功能,这就是单一职责。比如电商系统里的库存处理,一大坨上百行甚至几百行的代码,这就没遵守单一职责,同事看到你这样的代码时,想打人,当场崩溃。

    以下是单一职责的代码范例,伪代码。下文所有代码都是伪代码,只为说明问题、表达思想,你可以用任何语言实现它。

    # 库存处理
    function Inventory(){
    	//先判断库存是否足够
    	bool have = haveInventory();
    	//如果库存不够,则生成补货单
    	if(!have){
    		bool result = replenishmentOrder();
    		if(!result) {
    		//补货单生成失败,返回错误
    		}
    	}
    	//更新库存
    	bool result = updateInventory();
    	if(!result) {
    		//库存更新失败,返回错误
    	}
    	//写日志
    	inventoryLog();
    }
    
    # 判断库存是否足够
    function haveInventory(){
    //具体业务
    }
    
    # 更新库存
    function updateInventory(){
    //具体业务
    }
    
    # 生成补货单
    function replenishmentOrder(){
    //具体业务
    }
    
    // 写日志
    function inventoryLog(){
    //具体业务
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    高内聚,低耦合

    这里只作简单介绍,只需了解这个概念即可。
    低耦合:指的是不同的模块之间关联性低。比如模块A操作模块B内的数据、改了模块B的代码然后导致模块A出故障,都属于高耦合。

    高内聚:模块内部的元素, 关联性越强, 则内聚越高, 模块单一性更强。 一个模块应当尽可能独立完成某个功能。

    面向对象

    注意了,这个是重点。

    我们常常接触到这个概念,那么到底什么是面向对象?它主要解决什么问题?

    1 先来看一个例子,企业中经常用到的功能:支付。

    这是一个反例,千万别写出这样的代码。但我们却常常会看见这样的代码,很痛苦。增加一个支付方式就要多加一个判断,每个判断里再写一大坨代码,改了这儿导致那儿用不了。耦合度非常高、代码非常冗长、增加或修改一个支付方式时牵扯太多。

    # 支付入口
    function payment(string code){
    	if(code=='alipay'){
    	//支付宝支付
    	}
    	elseif(code=='wechat'){
    	//微信支付
        }
        elseif(code=='xinyunfu'){
    	//幸运付
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2 面向对象,有三个主要特征:封装、继承、多态。
    封装:很好理解,同样的代码别在这里写了一次又在那里写一次,要封装起来让它可复用。比如判断用户余额是否足够,用户下单时写几行代码判断、提现时又写几行相同的代码进行判断、礼品兑换时又写几行相同的代码进行判断、以及其它很多地方。以后判断用户余额的逻辑需要变更时,就完了,眼泪都会掉下来。

    继承:一个类继承另外一个类,也就是一个子类继承一个父类。用此办法来达到继承父类的功能,或者重写父类的功能。

    多态:多种形态。多个子类继承同一个父类就能达到多态的效果。通俗点讲指的是一个动作出现不同的效果。比如“评论”这个动作,是个抽象概念,调用评论方法,结果可能是对文章进行评论、也可能是对商品进行评论。再比如支付模块的签名,签名是个抽象概念,具体的签名算法将由每个不同的支付厂商决定。

    我们来看一段代码,还是上面讲到的支付模块,一个很切合实际的很好的范例。

    # 支付模块
    
    # 支付入口 -- PaymentFactory.php
    class PaymentFactory{
    	public static function create(string $code){
    		//根据支付编码,创建对应的子类
    		$obj = new $code();
    		return $obj;
        }
    }
    # 基类 -- Base.php
    abstract class Base{
    	# 支付入口(各种处理,达到统一的支付入口的目的)
        public function payment(){
    		$this->sign();
    		$this->productsData();
    		$this->jump();
    		... 省略
    	}
    	# 签名。这是一个抽象方法,继承此类的子类必须实现它
    	abstract public function sign();
    	# 处理商品。这是一个私有方法,不对外公开。可以是通用的功能,且可在子类进行重写。
        private function productsData(){
    		//对订单里面的商品进行各种处理
    	}
    	# 跳转到支付厂商页面。
    	abstract public function jump();
    	# 回调方法
    	abstract public function callback();
    }
    
    # 具体的支付厂商,也就是子类。继承了Base类,自动拥有了Base类的所有功能和属性 -- Alipay.php
    class Alipay extends Base{
    	public function sign(){
    		//实现签名方法,具体算法的实现
    	}
    	# 重写父类的方法。如果不重写,直接删除此方法即可,会自动继承父类的方法。
        private function productsData(){
    		//对订单里面的商品进行各种处理
    	}
    	# 重写此方法
    	public function jump(){
    		//跳转进入支付页面
    	}
    	# 重写此方法
    	public function callback(){
    		//回调函数
    	}
    }
    
    # 微信支付 -- WechatPay.php 
    class WechatPay extends Base{
    	... 
    	//跟支付宝Alipay一样,继承了Base类。abstract方法是必须在子类实现的虚方法,其它的方法可重写也可直接复用。
    
    }
    
    
    # 实际使用
    //创建一个支付对象
    $obj = PaymentFactory::create('Alipay');
    //调用支付入口,进入支付页面
    $obj->payment();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    上面的代码结构是:
    1 一个抽象的支付基类
    2 每个支付厂商对应一个类,继承支付基类
    3 一个创建具体支付类的静态方法。
    这个支付模块,这样的代码,以后如果要新接入一个支付商,就只需新增一个对应的子类即可,不需要动其它代码,不影响现有功能;如果是修改某个支付商,也只需修改对应的子类。
    这就避免了修改这个功能导致那个功能不能用了、以前好好的功能突然不能用了。

    以上,就是面向对象的讲解,实际工作中经常使用。突然想起以前学C#的时候,老师说,面向对象编程,一切皆对象,那会儿我理解了好久都没太明白什么是面向对象。

    设计模式

    先恭喜你,你已经学会了一个设计模式,就是工厂模式,就是上面讲的面向对象的例子 – 支付模块。
    那么什么是设计模式呢?其实就是先人根据实际编程写代码做项目做产品时总结出的一些代码设计方案,一些固定套路,能让我们的代码扩展性非常好、维护性非常棒的代码编排方案。

    设计模式,在实际工作中经常使用,比如单例模式、门面模式、工厂模式、注册树模式等。

    但这里不细讲,大家自行去学,只需学一些最常用的模式,阅读其代码及思想。

  • 相关阅读:
    win10win11截图技巧——不用安装其他截图工具或者运行其他截图工具,就可以截图,win10和win11可用
    视频电影和字幕如何合并?
    85:第七章:开发前台首页、作家个人展示页、粉丝等功能:6:作家个人展示页,展示该作者的可展示文章列表,近期佳文;
    linux 应用层调用shell指令api.之popen 和system
    Java客户端_zkclient库操作Zookeeper
    nginx的4层和7层代理的区别(附OSI网络模型)
    【AI应用】NVIDIA Tesla V100-PCIE-32GB的详情参数
    对音频切分成小音频(机器学习用)
    2023-9-8 求组合数(二)
    图形/多段线内缩外扩思路
  • 原文地址:https://blog.csdn.net/wuguandi/article/details/127528300