面向对象编程的六大原则(1)--单一职责原则

什么是单一职责

  单一职责原则(Single responsibility principle,简称SRP),顾名思义,是指一个类或者一个模块应该有且只有一个职责,它是面向对象编程六大原则之一。

单一职责的粒度

  单一职责的粒度,可以是某个方法、某个类、某个程序包甚至某个功能、某个模块(甚至某个系统),每一个层次上都可以进行单一职责设计。下面来举个例子说明一下:

  模块级别:某购物平台,包含如下几个模块:用户模块、商品模块、订单模块、库存模块、运输模块、支付模块,每一个模块都已本身的职责:用户模块负责用户相关的功能,商品模块负责商品的管理等等;

  功能级别:在模块内部,比如用户模块,根据用户相关职责划分,又划分为用户管理、注册、登录等不同的功能,他们的职责也都是各不相同的;

  程序包级别:在用户管理中,又可以根据层次不同划分为持久化层、业务逻辑层、UI层,其中每一层基本上就是一个程序包,持久化层负责数据持久化相关(和数据库打交道,数据的CRUD(增删改查)),业务逻辑层负责用户管理相关的业务逻辑(比如修改密码),UI层负责用户界面交互;

  类级别:在持久化层内部,又可以根据职责不同划分为:数据库连接类(负责数据库连接的构造)、持久化类(负责数据的CRUD操作)、数据缓存类(负责数据缓存的处理)等;

  方法级别:在持久化类中,又可以划分为查询数据方法(负责查询数据)、检索数据方法(负责检索数据)、新增数据方法(负责插入数据)、 删除数据方法(负责删除数据)、修改数据方法(负责修改数据)。有些复杂场景,甚至建议增删改查每一个逻辑都放到不同的类中;

  方法级别二:在查询数据方法中,又可以根据查询的逻辑步骤划分为不同的二级方法:解析查询条件方法、构造Sql方法、执行Sql方法、构造返回实体方法;每个方法可以借着这个思路再往下细化;

单一职责的优点

  1. 增强功能的稳定性
    单一职责能够增强功能稳定性、健壮性,适应程序的变化,避免修改一段逻辑时,对其他逻辑造成影响。例如:一个类或者一个方法,承担了多个职责:职责A、职责B、职责C...职责N。如果在维护过程中,修改之职责A对应的逻辑,就很有可能对职责B、C等其他职责逻辑造成影响,最终不利于功能的稳定性。
  2. 提升复用能力
    使用单一职责,有一某一个类或者方法都是对应的它本身的唯一职责,已经是实现某个职责的最小粒度,所以它可以提供给任何需要该职责地方调用,从而提升了复用能力。
  3. 降低程序复杂度
    由于单一职责原则是根据职责来设计,每一个类或者方法只实现某一特定的逻辑,粒度划分的合适的话,每一个类基本上只有几行、至多几十行代码,程序复杂度会被大大降低;
  4. 提升可读性
    每一个程序包、类、方法职责明确后,我们在阅读代码时,我们可以通过方法名就能知道某个方法是干什么的(可以不用知道具体的细节),它内部用到的方法是干什么的,有助于我们在某一层次上思考代码逻辑是否正确、完整,而不用受某一具体细节逻辑的影响。

具体实践

  在用户管理持久化层,如果要适配不同类型的数据库(比如要支持SqlServer、Oracle、MySql等),不同类型的数据库,其语法结构都有一些差异,比如插入数据方法,插入sql的语法是不同的。我们可能按照如下代码实现:

  以下是用户信息的结构:

    public class UserInfo
    {
        public string ID { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
    }

  以下是用户持久化的新增数据方法:

  

    public class UserDac
    {
        Database GetDatabase()
        {
            /*获取Database连接的逻辑*/
        }

        //新增用户
        public void AddUser(UserInfo userInfo)
        {
            Database db = GetDatabase();
            string insertSql = string.Empty;
            switch (db.DbType)
            {
                case DBType.SqlServer:
                    insertSql = "Sql A";
                    break;
                case DBType.Oracle:
                    insertSql = "Sql B";
                    break;
                default:
                    throw new NotSupportedException("DBType");
            }
            db.ExecuteSql(insertSql);
        }
    }

  在上面的例子中,我们看似应该是一个比较简单并且合理的结构。但是假如有以下需求场景:

    1、我的业务中添加了新的字段,需要修改 InsertSql(在Sql中添加新字段部分);

    2、我需要添加一种新的数据库类型支持(假如需要支持开源的MySql),新的数据库类型中,Sql语法也是不相同的;

  两个场景都需要修改以上的代码,这说明上面这段代码承担了两个职责,违背了单一职责原则。

  从上面的方法中,我们可以看到 ,上面方法承担了两个职责:拼接插入Sql;适配不同的数据库类型。我们可以按照如下方式进行修改(修改中用到了设计模式中的策略模式)。

   用户信息的结构不变:

    public class UserInfo
    {
        public string ID { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
    }

  第一步:我们添加一个获取Sql的策略,如下结构:

    public interface IUserSqlStrategy
    {
        string GetInsertSql(UserInfo userInfo);
    }

  第二步:我们添加SqlServer的策略实现:

    public class SqlServerUserSqlStrategy : IUserSqlStrategy
    {
        public string GetInsertSql(UserInfo userInfo)
        {
            return "Sql A";
        }
    }

  第三步:相应的,我们添加Oracle、MySql的的实现类:

    public class OracleUserSqlStrategy : IUserSqlStrategy
    {
        public string GetInsertSql(UserInfo userInfo)
        {
            return "Sql B";
        }
    }

    public class MySqlUserSqlStrategy : IUserSqlStrategy
    {
        public string GetInsertSql(UserInfo userInfo)
        {
            return "Sql C";
        }
    }

  第四步,我们添加策略工厂,来根据不同的数据库类型获取不同的策略实现:

    public class UserSqlStrategyFactory
    {
        public static IUserSqlStrategy GetUserSqlStragety(DBType dbType)
        {
            switch (dbType)
            {
                case DBType.SqlServer:
                    return new SqlServerUserSqlStrategy();
                case  DBType.Oracle:
                    return new OracleUserSqlStrategy();
                case DBType.MySql:
                    return new MySqlUserSqlStrategy();
                default:
                    throw new NotSupportedException("DBType");
            }
        }
    }

  最后,执行插入逻辑中,调用策略工厂获取策略,然后根据相应的策略获取不同的Sql实现:

    public class UserDac
    {
        Database GetDatabase()
        {
            /*获取Database连接的逻辑*/
        }

        //新增用户
        public void AddUser(UserInfo userInfo)
        {
            Database db = GetDatabase();
            var strategy = UserSqlStrategyFactory.GetUserSqlStragety(db.DbType);
            string insertSql = strategy.GetInsertSql(userInfo);
            db.ExecuteSql(insertSql);
        }
    }

  以上是所有的代码实现,通过策略模式,将不同数据库类型的实现拆分到不同的策略实现类中,这样拼接插入Sql逻辑与适配不同数据库逻辑两个职责拆分开来。

 总结

  通过单一职责原则,将程序实现拆分到不同的类(或者方法)中,这样,以后的变化都只影响要修改的主责,而不会影响到其他职责,最终达到提升稳定性的目的。

原文地址:https://www.cnblogs.com/silencer/p/10812466.html

时间: 2024-10-06 14:50:13

面向对象编程的六大原则(1)--单一职责原则的相关文章

面向对象编程6大设计原则:单一职责原则

单一职责原则(Single  Responsibility Principle)简称SRP原则. 定义 应该有且仅有一个原因引起类的变更. 优点 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多: 提高类的可读性,提高系统的可维护性: 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响. 说明 单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则: 单一职责原则要根据项目的实际情

面向对象设计原则:单一职责原则(The Single Responsibility Principle)

热爱生活.享受娱乐.专注技术,欢迎关注微信公众号QGer,我们一起见证成长! 什么是单一职责原则? - 官方解释:一个类应该只有一种改变的原因 - 通俗解释:一个类被修改.拓展的时候,应该只能因为一种职责(功能)的扩展,而不应该有第二种职责导致类的修改,一个也不能有另一种职责存在. 为什么遵循单一职责原则? 降低类的复杂度,一个类负责一种职责,逻辑上也变得直观简单. 使代码变得灵活,提高系统的维护性. 变更的风险降低,有需求就会有变更,单一职责原则可降低变更的影响面. 保持松耦合,提供内聚. 如

设计模式六大原则之单一职责原则

一.什么是设计模式 设计模式:设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.由此可见,设计模式不是代码复用而是经验复用.是代码设计的经验总结. 设计模式的六大原则:[单一职责.里氏替换.依赖倒置.接口隔离.迪米特法则.开闭] 23中常用的设计模式: [单例模式.工厂模式.抽象工厂模式.模板模式.代理模式.建造者模式.原型模式.中介者模式. 命令模式.装饰模式.策略模式.责任链模式.适配模式.迭代器模式.组合模式.观察者模式.备忘录模式

面向对象设计原则之单一职责原则(SRP)

Web程序猿博客:http://blog.csdn.net/thinkercode 这条原则曾经在 Tom DeMaro 和 Meilir Page-Jones 的著作中描述过,并称之为内聚性(cohesion).他们把内聚性定义为:一个模块的组成元素之间的功能相关性. 单一职责原则(SRP) 单一职责原则(Single Responsibility Principle, SRP):就一个类而言,应该仅有一个引起它变化的原因. 单一职责的原则告诉我们:在软件系统中,如果一个类承担的职责过多,就等

面向对象设计原则之单一职责原则

单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小.单一职责原则定义如下: 单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因. 单一职责原则告诉我们:一个类不能太“累”!在软件系统中,一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小,而且一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的

设计模式(三)面向对象设计原则之单一职责原则

引用自:http://blog.csdn.net/lovelion  作者:刘伟 单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小.单一职责原则定义如下: 单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责, 或者可以定义为:就一个类而言,应该只有一个引起它变化的原因. 单一职责原则告诉我们:一个类不能太"累"!在软件系统中,一个类(大到模块,小到方法)承担的 职责越多,它被复用的可能性就越小,而

学习设计模式 - 六大基本原则之单一职责原则

设计模式总共有六大基本原则,统称为SOLID (稳定)原则,分别是S-单一职责原则(Single Responsibility Principle), O-开闭原则(Open closed Principle),L-里氏替换原则(Liskov Substitution Principle),L-迪米特法则(Law of Demeter),I-接口隔离原则(Interface Segregation Principle),D-依赖倒置原则(Dependence Invension Principl

面向对象五大原则_1.单一职责原则&2.里氏替换原则

单一职责原则:Single Responsibility Principle (SRP) 一个类.仅仅有一个引起它变化的原因.应该仅仅有一个职责.每个职责都是变化的一个轴线.假设一个类有一个以上的职责,这些职责就耦合在了一起.这会导致脆弱的设计.当一个职责发生变化时,可能会影响其他的职责.另外,多个职责耦合在一起,会影响复用性. 比如:要实现逻辑和界面的分离. T负责两个不同的职责:职责P1.职责P2.当因为职责P1需求发生改变而须要改动类T时.有可能会导致原本执行正常的职责P2功能发生问题.

day01_面向对象五大原则_1.单一职责原则&2.里氏替换原则

单一职责原则:Single Responsibility Principle (SRP) 一个类,只有一个引起它变化的原因.应该只有一个职责.每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起.这会导致脆弱的设计.当一个职责发生变化时,可能会影响其它的职责.另外,多个职责耦合在一起,会影响复用性.例如:要实现逻辑和界面的分离. T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障.也就是

设计原则之单一职责原则

定义:一个类只负责一项职责,应该只有一个能引起它变化的原因. 问题:类T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常 的职责P2功能发生故障. 解决:分别建立两个类T1.T2,使T1完成职责P1功能,T2完成职责P2功能.这样,当修改类T1时,不会使职责P2发生故障风险: 同理,当修改T2时,也不会使职责P1发生故障风险. 举个栗子:介绍几种动物的栖息地和食物,这里边有两项职责:栖息地和食物. 用一个类Recommend介绍牛生活在