面向对象七大基本原则
案例需求: 一个人想买一个电脑。
简单实现:
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大基本原则的理解,总结以下:单一原则,开闭原则,里氏替换,抽象接口,依赖倒置,迪米特法则
浙公网安备 33010602011771号