zoukankan      html  css  js  c++  java
  • 面向对象七大基本原则

    案例需求: 一个人想买一个电脑。

    简单实现:

    class User {
        getComputer () {
            console.log('跑很远去买220v电源'),//表达的是这个过程很复杂,
            console.log('跑很远买16存显示器')
            //。。。。。
            console.log('组装');
        }
    };
    new User().getComputer();

    上面的实现满足了我的需求。但是有个问题:在getComputer方法中,每次都要跑很远去买,然后自己组装,整个过程繁琐复杂(脑补getComputer方法内部的代码很长很长)。如果能有人送货,就好了。

    解决思路就是单一原则: 一个类或方法只做一件事。

    class User {
        dianyuan(num) {
            console.log(`买了个${num}v电源`)
        }
        screen(num) {
            console.log(`买了个${num}寸显示器`)
        }
        zz() {
           console.log('组装') 
        }
        getComputer () {
            this.dianyuan(220);
            this.screen(20);
            
            //。。。。。
            this.zz();
        }
    };
    new User().getComputer();
    

     在新实现中,我随便打几个电话(将不同类型的零件单独定义为各自的函数,调用dianyuan/screen...,实现单一原则),就能得到想要类型的零件。但是,不是每个人都像我这样了解电脑零件及组装过程的,对于小白来说,它希望有个经销商能直接帮他完成零件购买及组装的过程,

    解决思路:再次使用单一原则

    class Computer {
        dianyuan() {
            console.log(`买了个200v电源`)
        }
        screen(num) {
            console.log(`买了个17寸显示器`)
        }
        all() {
            this.dianyuan();
            this.screen();
        }
    }
    class User {
        
        zz() {
           console.log('组装') 
        }
        getComputer () {
            let computer = new Computer(220, 20);
            computer.all();
            this.zz();
        }
    };
    new User().getComputer();
    

      

      这次实现中, 我将获取零件的过程封装成了一个类,它能返回组装一个电脑所需要的所有零件;从此小白获取一个电脑的方法就是调用以下Computer.all()方法。但是只有一个经销商实在是太被动了,我不能货比三家,我希望所有的经销商都具备获取所有零件的能力,但是各自零件的类型及价钱又能让我可以选择。

    解决思路:

    1抽象:抽取事物的本质,剔除具体表现。

    2里氏替换:子类能够出现在所有父类出现的地方。

    3依赖倒置:程序应该依赖抽象接口, 而不依赖具体实现。

    class SuperComputer {
        dianyuan() {
    
        }
        screen() {
    
        }
        all() {
            this.dianyuan();
            this.screen();
        }
    }
    
    class SubOneComputer extends SuperComputer{
        dianyuan() {
            console.log('我们家的220电源10元')
        }
        screen() {
            console.log('我们家17屏幕20元');
        }
    }
    
    class SubTwoComputer extends SuperComputer {
        dianyuan() {
            console.log('我们家的220电源20元')
        }
        screen() {
            console.log('我们家17屏幕10元');
        }
    }
    
    class User {
        
        zz() {
           console.log('组装') 
        }
        getComputer (computer) {
            //为了程序的健壮性, 你需要判断这个参数是否是某经销商的实例(能够调用all()),从而产生某个经销商的依赖, 然后最好的实现方式就是判断它是否是某个抽象类的实例,避免对扩展子类的依赖, 这就是依赖倒置原则
            if (computer instanceof SuperComputer) {
                computer.all();
                this.zz();
            } else {
                console.log('请传入经销商的实例')
            }
        }
    };
    let  xiaoming= new User();
    xiaoming.getComputer(new SubOneComputer());
    let xiaohong = new User()
    xioahong.getComputer(new SubTwoComputer());

      小红/小明通过不同经销商那拿到不同类型的零件,但是零件肯定是齐全的,这得力于两点。

    1:抽象类SuperComputer为所有的经销商定义了标准(是不是有点抽象接口的概念)。

    2:经销商实现了SuperComputer定义的所有零件方法。这就是里氏替换带来的好处。

    3:为了User.getComputer()的健壮性, 你需要判断computer是否是某经销商的实例(能够调用all()),从而产生某个经销商的依赖, 然后最好的实现方式就是判断它是否是某个抽象类的实例,从而避免对扩展子类的依赖,毕竟抽象类的最可靠。

    然后 而不然后经销商又了新的问题, 为了盈利,他必须扩大业务范围。

    解决思路:

    开闭原则:对修改关闭, 对扩展开放

    class SuperComputer {
        dianyuan() {
    
        }
        screen() {
    
        }
        all() {
            this.dianyuan();
            this.screen();
        }
    }
    
    class SubOneComputer extends SuperComputer{
        dianyuan() {
            console.log('我们家的220电源10元')
        }
        screen() {
            console.log('我们家17屏幕20元');
        }
    
        paper() {
            console.log('A4纸1毛一张')
        }
    }
    
    class SubTwoComputer extends SuperComputer {
        dianyuan() {
            console.log('我们家的220电源20元')
        }
        screen() {
            console.log('我们家17屏幕10元');
        }
    
        netline() {
            console.log('网线1米2元')
        }
    }
    
    class User {
        
        zz() {
           console.log('组装') 
        }
        getComputer (computer) {
            //为了程序的健壮性, 你需要判断这个参数是否是某经销商的实例(能够调用all()),从而产生某个经销商的依赖, 然后最好的实现方式就是判断它是否是某个抽象类的实例,避免对扩展子类的依赖, 这就是依赖倒置原则
            if (computer instanceof SuperComputer) {
                computer.all();
                this.zz();
            } else {
                console.log('请传入经销商的实例')
            }
        }
    };
    let  xiaoming= new User();
    xiaoming.getComputer(new SubOneComputer());
    let xiaohong = new User()
    xioahong.getComputer(new SubTwoComputer());
    

      上面的两个经销商为了利润, 各自扩大了经营范围(paper(), netline()),他们是对SupterComputer的扩展,而不能为单独的经销商在SuperComputer类中去添加跟电脑零件无关的方法,保证抽象的单一性,稳定性。

    还有一个问题, 现在所有的小白能轻松的从不同的经销商那里获取全部零件,但是还是要自己组装, 还不够方便,其实小白们只需要找到一个会组装的人,这个组装的人肯定对于电脑零件是非常熟悉的,小白们不在关心电脑零件问题,。

    解决思路: 

    迪米特法则:一个对象应该对其他对象保持最少的了解

    class SuperComputer {
        dianyuan() {
    
        }
        screen() {
    
        }
        all() {
            this.dianyuan();
            this.screen();
        }
    }
    
    class SubOneComputer extends SuperComputer{
        dianyuan() {
            console.log('我们家的220电源10元')
        }
        screen() {
            console.log('我们家17屏幕20元');
        }
    
        paper() {
            console.log('A4纸1毛一张')
        }
    }
    
    class SubTwoComputer extends SuperComputer {
        dianyuan() {
            console.log('我们家的220电源20元')
        }
        screen() {
            console.log('我们家17屏幕10元');
        }
    
        netline() {
            console.log('网线1米2元')
        }
    }
    
    //组装类
    class InitComputer {
        software() {
            console.log('安装软件')
        }
       
        hardware(computer) {
            if (computer instanceof SuperComputer) {
                computer.all();
            } else {
                console.log('请传入经销商的实例')
            }
        }
        zz(money) {
            switch(money)
            {
                case 5000: 
                    this.hardware(new SubOneComputer());//5000元的配置
                case 4000:
                    this.hardware(new SubTwoComputer());//4000元的配置
            }
            this.software();
            console.log('组装完毕');
        }
    }
    class User {
        
        getComputer (money) {
            new InitComputer().zz(money);
        }
    };
    let  xiaoming= new User();
    xiaoming.getComputer(4000);
    let xiaohong = new User()
    xioahong.getComputer(5000);
    

      终于搞定了,现在小白只需要给组装类money就能得到一台相应配置的电脑, 不用在找经销商及自己组装了。这就是迪米特法则, 小白不需要熟悉经销商的套路,而是通过组装类这个中间人去搞定。

    以上的例子是我对公司培训面向对象6大基本原则的理解,总结以下:单一原则,开闭原则,里氏替换,抽象接口,依赖倒置,迪米特法则

  • 相关阅读:
    LightOJ 1030 Discovering Gold(期望)
    CodeForces 567B Berland National Library
    HDU
    HDU
    (模拟、进制转换)
    HDU
    HDU
    CodeForces 429 B B. Working out
    CodeForces 546 D. Soldier and Number Game(素数有关)
    2016中国大学生程序设计竞赛
  • 原文地址:https://www.cnblogs.com/pandapeter/p/10465068.html
Copyright © 2011-2022 走看看