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

前言

作为文集的第一篇,我觉得有必要介绍一下大概的写作规划。整个文集将分为三个部分,分别是面向对象六大原则、23种设计模式,以及MVC、MVP、MVVM三种应用架构的介绍和使用。

如果大家看过何红辉和关爱民老师著的《Android源码设计模式解析与实战》,就会觉得似曾相识。其实,我写这个文集的目的,就是为了巩固我看这本书后的感悟,让我能加深对内容的理解。

像我们平时工作,通常都是先实现所给的功能,等到修改或者扩展时,发现不方便,再结合问题重构模块。其实有些是可以避免的,面向对象六大原则在类这个层次上告诉我们,如何构造类、如何维护类之间的关系;23种设计模式在功能的层次上指导我们写出精炼完善的代码;而应用架构的变迁反映了App层次上应用功能、资源的增加,导致维护成本的提高,急需细化模块。

1、现实中的场景

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

2、代码描述现象

新建一个项目,用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();

}

}

3、单一职责原则

定义:一个类,应该仅有一个引起它变化的原因。

目的:让一个类专注于自身的功能。

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

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的代码减少了,功能更明确了。当设计团队和原型公司内部发生变化时,不会影响工厂的生产流程。

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

定义:类、模块、函数等应该对于扩展是开放的,对于修改是封闭的。

目的:在软件扩展的过程中,确保原有功能的正确性。

实例:上面的案例,已经细分了生产责任。我们就工厂来看,如果接到了公司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();

}

}

区别:继承父类和实现接口的区别就是里氏替换和依赖倒置的区别。继承可以拥有父类的所有属性和方法,减少创建类的成本,但同时会造成系统耦合,子类代码冗余,灵活性降低。接口正好相反,与之互补。

总结:开闭原则在工作中一定要实现,至于是用里氏替换还是依赖倒置,就根据当时的需求分析。

5、接口隔离原则

定义:类所依赖的接口应该仅仅包含所需要的功能。

目的:使接口的功能更加具体,类似单一职责,不过这是用于接口,使调用者只关注自己所需的功能。

实例:就拿声明设计规范的Designer来说,根据依赖倒置原则,将其改为接口,为了比较说明,添加了作为人所具有的吃饭的能力:

public interface Designer {

// 此处声明设计师具有吃饭的能力

// 与为工厂设计图纸不相关,理应去掉

void eat();

void design();

}

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

6、迪米特原则

定义:一个类应该仅仅依赖于自己需要调用的对象。

目的:保证逻辑结构的清晰,降低系统的耦合程度。

实例:就拿负责生产的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();

}

}

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

Java高架构师、分布式架构、高可扩展、高性能、高并发、性能优化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战学习架构师视频免费获取架构群:854180697

群链接:加群链接

写在最后:欢迎留言讨论,加关注,持续更新!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容