白话设计模式原则

为什么需要设计模式

其实没有设计模式我们也能完成开发工作。但是为什么需要设计模式呢?让你看起来很牛,没错这个算一个。让你的代码层次感分明,可读性强而且容易维护。让你像我一样有更多的摸鱼划水时间。

可能有人说我一个类或者方法就干完的东西,你搞了七八个。当然使用设计模式也是要斟酌的。一些简单稳定的业务也不推荐使用设计模式。设计模式多用于复杂多变的业务或者要求适配性、扩展性更强的场景中。不要为了设计模式而设计模式。

接下来我们结合实际开探讨一下设计模式的一些原则。

开闭原则


public class Seller {

    public BigDecimal sellCar(Car car) {
        return car.getPrice();
    }

}

上面模拟4S店一个销售在卖车。突然老板搞了一个促销:在双十一要开展打折活动。在sellCar方法内增加一个计算可行吗?这势必影响整个业务,导致所有车都打折。不行不行!那么在Car里面操作?然后你改啊改!结果各种逻辑流程判断。才实现了业务要求。如果后续打折活动结束了或者升级了,你还要再进行各种改动。你发现一个打折让你的代码面目全非、臃肿不堪。上面说了对于复杂而多变的业务使用设计模式就可以解决。那么设计模式最重要的一个原则就是开闭原则。也就是说
一个软件模型实体如类、模块和函数应该对扩展开放,对修改关闭。也就是需要我们将业务行为抽象出来,使用抽象来构建。具体的业务通过抽象的实现来解决。那么我们就搞一个DiscountCar来extends Car.这样sellCar是什么具体的实现就执行什么具体的逻辑。不会影响以前的逻辑,而且不会因为改动原来的代码影响其他逻辑。保证接口可靠性和稳定性。如下:

 public class DiscountCar extends Car{

    private BigDecimal price;
    private BigDecimal discount;

    @Override
    public BigDecimal getPrice() {
        return price.multiply(discount);
    }

 }

依赖倒置原则

还拿上面的例子来说。经过一系列的打折活动4S店的生意蒸蒸日上。老板突然想扩展一下周边,同时压榨一下销售。让他们卖车的同时卖点玻璃水、防冻液之类的。这个需求当然又抛给了苦逼的程序员。sellCar太具体了不能满足需要了。很多情况下你会增加一个卖玻璃水、卖防冻液的方法。如果以后增加了卖大米,甚至买起了鸡蛋饼呢?总不能一直增加方法吧。我们需要考虑这种问题。我们可以抽象所有卖东西的场景。然后我们把卖的物品抽象成了一个抽象化的概念(java对应的是接口,把卖的行为抽象成了sell方法:


public interface Any {

    String getName();

    BigDecimal getPrice();

}

public class Seller {

    public BigDecimal sell(Any any) {
        return any.getPrice();
    }
}

这样随便老板以后卖什么你都可以通过该方法进行处理了,只需要关注于Any的实现。

职责单一

4S店销售卖了一段东西后,发现对客户的吸引力度不大。突然脑子比较灵活的老板又想起了电影中的一句台词:少林功夫加唱歌跳舞有没有搞头? 对啊你们销售能不能搞搞什么唱、跳、Rap,当然打篮球就不要了别砸坏了车玻璃。但是人与人是不一样的,有的人只会唱,有的人只会跳,有的人可能唱跳Rap都会甚至篮球都很溜。所以为了适配这么多情况,我们必须把每种技能独立出来,根据不同的人来组合这些技能。


public class Seller implements Sing, Jump, Rap {

    public BigDecimal sell(Any any) {
        return any.doSell();
    }

    @Override
    public void sing() {
        System.out.println("seller sing ");
    }

    @Override
    public void jump() {
        System.out.println("seller jumping ");
    }

    @Override
    public void rap() {
        System.out.println("seller raping ");
    }
}

但是注意一定要适度,根据业务来细分。否则会导致接口过多反而增大开发难度以及代码的复杂度。

迪米特法则

新的销售方法搞了一段时间后,老板想看看检验一下他这个馊主意的效果。于是就叫了一个销售让他提供一份报表出来看看。那么程序员该如何实现老板查看报表功能呢,很可能有人会这么写:

public class Boss {
    private Seller seller;
    private Report report;

    public void read() {
        seller.apply(report);
    }
}

乍看功能实现了,细看会发现逻辑不对。哪里不对呢?老板已经持有了报表,如果老板已经知道了你的业绩还叫你干什么?这种逻辑肯定是不对的!也就是说Boss直接依赖了Report;而这个Report不应该直接由Boss处理,而应由Seller控制。

public class Boss {
    private Seller seller;

    public void read(){
         seller.apply();
    }

}

public class Seller {
      private Report report;

      public void apply(){
         report.show();
      }

}

这种最大化隔离了类与类之间的关系。降低了类之间的耦合。迪米特法则因此又得名最少知道原则。

接口隔离原则

用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。一个类对一个类的依赖应该建立在最小的接口上。

建立单一接口,不要建立庞大臃肿的接口尽量细化接口,接口中的方法尽量少,尽量细化接口。注意适度原则,一定要适度。不能滥用
就像上面的唱跳 rap,分离是最好的。

里氏代换原则

这里主要针对类的继承关系而言。比较正式的定义:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2 时,程序P的行为没有发生变化,那么类型 S 是类型 T 的子类型。
在4S店老板眼里,只要新来的能在销售岗位上像销售老手一样卖出汽车,他就是一名合格的销售。感觉这种定义就像一句名言:不管你黑猫白猫,能抓老鼠的都是好猫。

从某种含义上里氏代换有着以下的契约:

  1. 子类必须完全实现父类的方法。父类出现的地方子类都可以代替父类。
  2. 子类可以有自己的个性定义。 里氏替换原则 可以正着用,但是不能反过来用。在子类出现的地方,父类未必就可以胜任。子类一般比父类有个性。
  3. 覆盖或实现父类的方法时输入参数可以被放大。如果4S店老板规定基础车谈价的折扣最多九折,销售打个九五折没有问题,打八折老板肯定要跟你说道说道了。
  4. 覆写或实现父类的方法时输出结果可以被缩小。同样是15W本来只能卖出给客户一个乞丐版,结果换了个销售结果给出了一辆旗舰版。怕不是过不了试用期哦。

合成/复用原则

它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具体实现规范。

总结

这七种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同。其中,开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。在实际开发中我们可以根据业务来进行设计模式的使用,但是很重要的一点千万不要被这些条条框框束缚了你的手脚。

原创作者:码农小胖哥
转载地址:https://gper.club/articles/7e7e7f7ff7g58gc3g6e

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

推荐阅读更多精彩内容

  • 为什么需要设计模式 其实没有设计模式我们也能完成开发工作。但是为什么需要设计模式呢?让你看起来很牛,没错这个算一个...
    码农小胖哥阅读 163评论 0 1
  • 目录: 设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒...
    加油小杜阅读 719评论 0 1
  • 转载标注声明:http://www.uml.org.cn/sjms/201211023.asp 目录:[设计模式六...
    Bloo_m阅读 706评论 0 7
  • 什么是设计模式 在GoF(Gang of Four)的书籍《Design Patterns - Elements ...
    zhrowable阅读 1,007评论 0 1
  • 文/图:蒋氏蜜语(永州·零陵) 时至仲夏,梳子铺乡下农村到处一片欣欣向荣。树叶翠绿一片,七十二峰披...
    蒋六元阅读 916评论 1 3