如何提高代码的扩展性(6)

简介: 如何提高代码的扩展性(6)

1、场景举例分析


二、场景示例
下面就以我们传统行业的订单操作为例来说明下接口隔离的必要性。
1、胖接口
软件设计最初,我们的想法是相同功能的方法放在同一个接口里面,如下,所有订单的操作都放在订单接口IOrder里面。理论上来说,这貌似没错。我们来看看如何设计。
   public interface IOrder
    {
        //订单申请操作
        void Apply(object order);
        //订单审核操作
        void Approve(object order);
        //订单结束操作
        void End(object order);
    }
刚开始只有销售订单,我们只需要实现这个接口就好了。
    public class SaleOrder:IOrder
    {
        public void Apply(object order)
        {
            throw new NotImplementedException();
        }
        public void Approve(object order)
        {
            throw new NotImplementedException();
        }
        public void End(object order)
        {
            throw new NotImplementedException();
        }
    }
后来,随着系统的不断扩展,我们需要加入生产订单,生产订单也有一些单独的接口方法,比如:排产、冻结、导入、导出等操作。于是我们向订单的接口里面继续加入这些方法。于是订单的接口变成这样:
    public interface IOrder
    {
        //订单申请操作
        void Apply(object order);
        //订单审核操作
        void Approve(object order);
        //订单结束操作
        void End(object order);
        //订单下发操作
        void PlantProduct(object order);
     //订单冻结操作
        void Hold(object order);
        //订单删除操作
        void Delete(object order);
        //订单导入操作
        void Import();
        //订单导出操作
        void Export();
    }
我们生产订单的实现类如下
    //生产订单实现类
    public class ProduceOrder : IOrder
    {
        /// <summary>
        /// 对于生产订单来说无用的接口
        /// </summary>
        /// <param name="order"></param>
        public void Apply(object order)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 对于生产订单来说无用的接口
        /// </summary>
        /// <param name="order"></param>
        public void Approve(object order)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 对于生产订单来说无用的接口
        /// </summary>
        /// <param name="order"></param>
        public void End(object order)
        {
            throw new NotImplementedException();
        }
        public void PlantProduct(object order)
        {
            Console.WriteLine("订单下发排产");
        }
     public void Hold(object order)
        {
            Console.WriteLine("订单冻结");
        }
        public void Delete(object order)
        {
            Console.WriteLine("订单删除");
        }
        public void Import()
        {
            Console.WriteLine("订单导入");
        }
        public void Export()
        {
            Console.WriteLine("订单导出");
        }
    }
销售订单的实现类也要相应做修改
    //销售订单实现类
    public class SaleOrder:IOrder
    {
        public void Apply(object order)
        {
            Console.WriteLine("订单申请");
        }
        public void Approve(object order)
        {
            Console.WriteLine("订单审核处理");
        }
        public void End(object order)
        {
            Console.WriteLine("订单结束");
        }
        #region 对于销售订单无用的接口方法
        public void PlantProduct(object order)
        {
            throw new NotImplementedException();
        }
     public void Hold(object order)
        {
            throw new NotImplementedException();
        }
        public void Delete(object order)
        {
            throw new NotImplementedException();
        }
        public void Import()
        {
            throw new NotImplementedException();
        }
        public void Export()
        {
            throw new NotImplementedException();
        } 
        #endregion
    }
需求做完了,上线正常运行。貌似问题也不大。系统运行一段时间之后,新的需求变更来了,要求生成订单需要一个订单撤销排产的功能,那么我们的接口是不是就得增加一个订单撤排的接口方法CancelProduct。于是乎接口变成这样:
public interface IOrder
    {
        //订单申请操作
        void Apply(object order);
        //订单审核操作
        void Approve(object order);
        //订单结束操作
        void End(object order);
        //订单下发操作
        void PlantProduct(object order);
        //订单撤排操作
        void CancelProduct(object order);
        //订单冻结操作
        void Hold(object order);
        //订单删除操作
        void Delete(object order);
        //订单导入操作
        void Import();
        //订单导出操作
        void Export();
    }
这个时候问题就来了,我们的生产订单只要实现这个撤销的接口貌似就OK了,但是我们的销售订单呢,本来销售订单这一块我们不想做任何的变更,可是由于我们IOrder接口里面增加了一个方法,销售订单的实现类是不是也必须要实现一个无效的接口方法?这就是我们常说的“胖接口”导致的问题。由于接口过“胖”,每一个实现类依赖了它们不需要的接口,使得层与层之间的耦合度增加,结果导致了不需要的接口发生变化时,实现类也不得不相应的发生改变。这里就凸显了我们接口隔离原则的必要性,下面我们就来看看如何通过接口隔离来解决上述问题。
2、接口隔离
我们将IOrder接口分成两个接口来设计
    //删除订单接口
    public interface IProductOrder
    {
        //订单下发操作
        void PlantProduct(object order);
        //订单撤排操作
        void CancelProduct(object order);
        //订单冻结操作
        void Hold(object order);
        //订单删除操作
        void Delete(object order);
        //订单导入操作
        void Import();
        //订单导出操作
        void Export();
    }
    //销售订单接口
    public interface ISaleOrder
    {
        //订单申请操作
        void Apply(object order);
        //订单审核操作
        void Approve(object order);
        //订单结束操作
        void End(object order);
    }
对应的实现类只需要实现自己需要的接口即可
    //生产订单实现类
    public class ProduceOrder : IProductOrder
    {
        public void PlantProduct(object order)
        {
            Console.WriteLine("订单下发排产");
        }
        public void CancelProduct(object order)
        {
            Console.WriteLine("订单撤排");
        }
        public void Hold(object order)
        {
            Console.WriteLine("订单冻结");
        }
        public void Delete(object order)
        {
            Console.WriteLine("订单删除");
        }
        public void Import()
        {
            Console.WriteLine("订单导入");
        }
        public void Export()
        {
            Console.WriteLine("订单导出");
        }
    }
    //销售订单实现类
    public class SaleOrder : ISaleOrder
    {
        public void Apply(object order)
        {
            Console.WriteLine("订单申请");
        }
        public void Approve(object order)
        {
            Console.WriteLine("订单审核处理");
        }
        public void End(object order)
        {
            Console.WriteLine("订单结束");
        }
    }


这样设计就能完美解决上述“胖接口”导致的问题,如果需要增加订单操作,只需要在对应的接口和实现类上面修改即可,这样就不存在依赖不需要接口的情况。通过这种设计,降低了单个接口的复杂度,使得接口的“内聚性”更高,“耦合性”更低。由此可以看出接口隔离原则的必要性。


另:

有称六大设计原则:+迪米特法则。


迪米特法则的定义是:只与你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to strangers)。其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。


举例:明星由于全身心投入艺术,所以许多日常事务由经纪人负责处理,如与粉丝的见面会,与媒体公司的业务洽淡等。这里的经纪人是明星的朋友,而粉丝和媒体公司是陌生人,所以适合使用迪米特法则,其类图如图 所示。


image.png

相关文章
|
6月前
|
安全 Java
利用反射技术提升Java应用的灵活性和可扩展性
利用反射技术提升Java应用的灵活性和可扩展性
47 0
|
7月前
|
消息中间件 运维 监控
微服务架构的优点和缺点分别有哪些?
微服务架构的优点和缺点分别有哪些?
289 0
微服务架构的优点和缺点分别有哪些?
|
1月前
模块功能复用和扩展性
模块功能复用和扩展性 模块功能复用和扩展性是软件工程中的重要概念,主要体现在设计和实现阶段。
22 1
|
9月前
|
设计模式 算法
如何优雅地使用策略模式来实现更灵活、可扩展和易于维护的代码?
如何优雅地使用策略模式来实现更灵活、可扩展和易于维护的代码?
57 0
|
存储 缓存 运维
系统稳定性设计原则:简单、冗余、标准化、健壮
系统稳定性设计原则:简单、冗余、标准化、健壮
547 0
系统稳定性设计原则:简单、冗余、标准化、健壮
|
存储 缓存 固态存储
如何写出高性能代码(四)优化数据访问
同一份逻辑,不同人的实现的代码性能会出现数量级的差异; 同一份代码,你可能微调几个字符或者某行代码的顺序,就会有数倍的性能提升;同一份代码,也可能在不同处理器上运行也会有几倍的性能差异;十倍程序员不是只存在于传说中,可能在我们的周围也比比皆是。十倍体现在程序员的方法面面,而代码性能却是其中最直观的一面。
116 0
如何写出高性能代码(四)优化数据访问
如何提高代码的扩展性(4)
如何提高代码的扩展性(4)
103 0
如何提高代码的扩展性(4)
|
测试技术 微服务
如何提高代码的扩展性(2)
如何提高代码的扩展性(2)
133 0
如何提高代码的扩展性(2)
|
程序员
如何提高代码的扩展性(3)
如何提高代码的扩展性(3)
322 0
如何提高代码的扩展性(3)
如何提高代码的扩展性(5)
如何提高代码的扩展性(5)
335 0
如何提高代码的扩展性(5)

热门文章

最新文章