被人忽视的面向对象的六大原则

作者: lanceJin | 来源:发表于2017-04-19 16:57 被阅读0次

    1.前言


    作为文集的第一篇,我觉得有必要介绍一下大概的写作规划。整个文集将分为三个部分,分别是面向对象六大原则、23种设计模式,以及MVC、MVP、MVVM三种应用架构的介绍和使用
      如果大家看过何红辉和关爱民老师著的《Android源码设计模式解析与实战》,就会觉得似曾相识。其实,我写这个文集的目的,就是为了巩固我看这本书后的感悟,让我能加深对内容的理解。
      像我们平时工作,通常都是先实现所给的功能,等到修改或者扩展时,发现不方便,再结合问题重构模块。其实有些是可以避免的,面向对象六大原则在类这个层次上告诉我们,如何构造类、如何维护类之间的关系;23种设计模式在功能的层次上指导我们写出精炼完善的代码;而应用架构的变迁反映了App层次上应用功能、资源的增加,导致维护成本的提高,急需细化模块。

    2.现实中的场景


    有一个工厂想生产一款产品,按照流程得先产生设计稿,然后根据设计稿做出产品原型,最后生产出产品。

    3.代码描述现象


    新建一个项目,用Factory代表工厂,通过productA方法显示生产产品A的流程,最后在程序入口Main中调用。

    public class Factory {
        
        public Factory() {
            super();
        }
        
        public void productA() {
            System.out.println("产生设计稿A");
            System.out.println("做出产品原型A");
            System.out.println("生产出产品A");
        }
    
    }
    
    public class Main {
    
        public static void main(String[] args) {
            new Factory().productA();
        }
    
    }
    

    4.单一职责原则


    定义:一个类,应该仅有一个引起它变化的原因。
      目的:让一个类专注于自身的功能。
      实例:我们来看看上面的案例,明显可以发现工厂的功能过于复杂,又是设计又是做原型又是生产,随着业务的增加会越来越臃肿,不方便管理,所以应该将设计和原型交给专业的第三方来做。根据这个原则,可以将代码做如下修改:

    public class DesignerA {
        
        public DesignerA() {
            super();
        }
        
        public void design() {
            System.out.println("产生设计稿A");
        }
    
    }
    
    public class CompanyA {
        
        public CompanyA() {
            super();
        }
        
        public void make() {
            System.out.println("做出产品原型A");
        }
    
    }
    
    public class Factory {
        
        private DesignerA mDesigner;
        private CompanyA mCompany;
        
        public Factory() {
            super();
            mDesigner = new DesignerA();
            mCompany = new CompanyA();
        }
        
        public void productA() {
            mDesigner.design();
            mCompany.make();
            System.out.println("生产出产品A");
        }
    
    }
    

    总结:Factory的代码减少了,功能更明确了。当设计团队和原型公司内部发生变化时,不会影响工厂的生产流程。

    5.开闭原则(由里氏替换原则、依赖倒置原则实现)


    定义:类、模块、函数等应该对于扩展是开放的,对于修改是封闭的。
      目的:在软件扩展的过程中,确保原有功能的正确性。
      实例:上面的案例,已经细分了生产责任。我们就工厂来看,如果接到了公司B的产品原型咋办,现在而言是生产不了的,没那功能呀。所以得增加功能:

    public class Factory {
    
        // 一些相关的初始化工作
    
        public void productA() {
            mDesigner.design();
            mCompany.make();
            System.out.println("生产出产品A");
        }
        
        public void productB() {
            // 关于产品B的设计、原型和生产
        }
    
    }
    

    可是,随着工厂的发展,功能会不断增加,总不能每次都整改工厂吧。所以,我们可以通过父类(里氏替换原则)或者接口(依赖倒置原则)来确定生产规范,符合的产品,工厂就能生产。下面用里氏替换原则做个示范:

    // 声明设计的规范
    public abstract class Designer {
        
        public Designer() {
            super();
            // 此处是子类不需要的
            System.out.println("开始进行产品设计");
        }
        
        public abstract void design();
    
    }
    
    // 声明原型的规范
    public abstract class Company {
        
        public Company() {
            super();
            // 此处是子类不需要的
            System.out.println("根据设计做原型");
        }
        
        public abstract void make();
    
    }
    
    // 符合规范的设计师A
    public class DesignerA extends Designer {
        
        public DesignerA() {
            super();
        }
    
        @Override
        public void design() {
            System.out.println("产生设计稿A");
        }
    
    }
    
    // 符合规范的产品公司A
    public class CompanyA extends Company {
        
        public CompanyA() {
            super();
        }
    
        @Override
        public void make() {
            System.out.println("做出产品原型A");
        }
    
    }
    
    public class Factory {
        
        private Designer mDesigner;
        private Company mCompany;
    
        // 工厂根据不同的设计和原型生产
        public Factory(Designer designer, Company company) {
            super();
            mDesigner = designer;
            mCompany = company;
        }
        
        public void product() {
            mDesigner.design();
            mCompany.make();
            System.out.println("生产出所需的产品");
        }
    
    }
    
    public class Main {
    
        public static void main(String[] args) {
            // 拿到设计图和产品原型,开始生产
            new Factory(new DesignerA(), new CompanyA()).product();
        }
    
    }
    

    区别:继承父类和实现接口的区别就是里氏替换和依赖倒置的区别。继承可以拥有父类的所有属性和方法,减少创建类的成本,但同时会造成系统耦合,子类代码冗余,灵活性降低。接口正好相反,与之互补。
      总结:开闭原则在工作中一定要实现,至于是用里氏替换还是依赖倒置,就根据当时的需求分析。

    6.接口隔离原则


    定义:类所依赖的接口应该仅仅包含所需要的功能。
      目的:使接口的功能更加具体,类似单一职责,不过这是用于接口,使调用者只关注自己所需的功能。
      实例:就拿声明设计规范的Designer来说,根据依赖倒置原则,将其改为接口,为了比较说明,添加了作为人所具有的吃饭的能力:

    public interface Designer {
        
        // 此处声明设计师具有吃饭的能力
        // 与为工厂设计图纸不相关,理应去掉
        void eat();
        
        void design();
    
    }
    

    总结:隐藏非相关功能,除了不暴露更多细节,增加用户学习成本,更能降低系统耦合性,提高应用灵活性。

    7.迪米特原则


    定义:一个类应该仅仅依赖于自己需要调用的对象。
      目的:保证逻辑结构的清晰,降低系统的耦合程度。
      实例:就拿负责生产的Factory来说,它同时含有Designer和Company。也就是只负责生产的工厂却要自己准备设计图纸和产品原型,这不符合现实情况,它应该只生产所有公司交给它的规范的产品:

    public abstract class Company {
    
        // 由公司和设计师打交道
        private Designer mDesigner;
        
        public Company(Designer designer) {
            super();
            designer.design();
            System.out.println("根据设计做原型");
        }
        
        public abstract void make();
    
    }
    
    public class Factory {
        // 工厂只和公司拿来的原型打交道
        private Company mCompany;
        
        public Factory(Company company) {
            super();
            mCompany = company;
        }
        
        public void product() {
            mCompany.make();
            System.out.println("生产出所需的产品");
        }
    
    }
    
    public class Main {
    
        public static void main(String[] args) {
            // 生产之前确定使用哪个公司的哪个设计师作品
            new Factory(new CompanyA(new DesignerA())).product();
        }
    
    }
    

    总结:通过对结果进行比较,发现修改后(右)的流程比修改前(左)的流程更加符合现实生产环境。

    开始进行产品设计          开始进行产品设计
    根据设计做原型            产生设计稿A
    产生设计稿A               根据设计做原型
    做出产品原型A             做出产品原型A
    生产出所需的产品          生产出所需的产品
    

    相关文章

      网友评论

        本文标题:被人忽视的面向对象的六大原则

        本文链接:https://www.haomeiwen.com/subject/iisqzttx.html