设计模式铺铺路(面向对象设计的原则一二)

大家好,我是本周的带班编辑 子悠(这个月来的早了点),本周由于轮班小哥懿在出差,所以就由我为大家排版并送出技术干货,大家可以在公众号后台回复“java”,获得作者 Java 知识体系/面试必看资料。


我们的知识星球马上就要开始更新设计模式了,在更新设计模式之前,我们是不是需要做一些准备呢?否则设计模式中一些遵循的原则大家会一头雾水,所以我今天来给大家说一些面向对象的七种原则,有人说是6种有人说是7种,我个人认为是7种,我就按照7种来说,今天我就介绍2种系统运维工资一般多少,下一篇文章将会继续介绍剩下的五种其他综合收益原则,这些原则也会在设计模式中出现,各位技术人,欢迎大家的踊跃参加呦。

前言

在面向对象的软件设计中,只有尽量降低各个模块之间的耦合度,才能提高代码的复用率,系统的可维护性、其他垃圾可扩展性才能提高。面向对象的软件设计中,有23种经典的设计模式,是一套前人代码设计经验的总结,如果把设计模式比作武功招式,那么设计原则就好比是内功心法ideal。常用的设计原则有七个,下文将具体介绍。

设计原则简介

  • 单一职责原则:专注降低类系统运维工作内容的复杂度,实现类要职责单一;
  • 开放关闭原则:所有面向对象原则的核心jar是什么意思,设计要对扩展开发,对修改关闭;
  • 里式替换原则:实现开放关闭原则的重要方式之一,设计不要破坏继承关系;
  • 依赖倒置原则:系统抽象化的具体实现,要求面向接口编程,是面向对象设计的主要实现机制之一;
  • 接口隔离原则:要求接jar口的方法尽量少,接口尽量细化;
  • 迪米特法则:降低系统其他业务收入的耦合度,使一个模块的修改尽量少的影响其他模块,扩展会相对容易;
  • 组合复用原则:在软件设计中单一职责原则,尽量使用组合/聚合而不是继承达到代码复用的目的。

这些设计原则并不说我们一定要遵循他们来进行设计,而是根据我们的实际情况去怎么去选择使用他们,来让我们的程序做的更加的完善。jared对jensen独占欲

单一职责原则

解释​:

就一个类而言,应该仅有一个引起它变化的原因,通俗的说,就是一个类只负责一项职责。

此原则的核心就是解耦和增强内聚性

那么为什么要使用单一职责原则:

如果一个类承担的职责过多,就等于把这些职责耦合在一起,其他应收款一个职责的变化可能会削弱或者抑identification制这个类完成其他职责的能力。这种耦合会导致脆弱的设计。

这也是他的优点,我们总结一下

​优点​​:

(1)降低类的复杂度;

(2)提高类的可读性,提高系统jar是什么意思的可维护性;

(3)降低变更引起的风险(降低对其他功能的影响)。

我们来举一些简单的例子来说明其他应收款是什么科目idea是什么意思下这个单一职责原则

​实例​​:

//我们用动物生活来做测试
class Animal{
public void breathe(String animal){
System.out.println(animal+"生活在陆地上");
}
}
public class Client{
public static void main(String[] args){
Animal animal = new Animal();
animal.breathe("羊");
animal.breathe("牛");
animal.breathe("猪");
}
}
运行结果
羊生活在陆地上
牛生活在陆地上
猪生活在陆地上

但是问题来了,动物并不是都生活在陆地上的,鱼就是生活在水中的,修改时如果遵循idea是什么意思单一职责原则,需要将 Animal 类细分为陆生动物类 Terrestrial,水生动物 Aquaideologytic,代码如下:

class Terrestrial{
public void breathe(String animal){
System.out.println(animal+"生活在陆地上");
}
}
class Aquatic{
public void breathe(String animal){
System.out.println(animal+"生活在水里");
}
}


public class Client{
public static void main(String[] args){
Terrestrial terrestrial = new Terrestrial();
terrestrial.breathe("羊");
terrestrial.breathe("牛");
terrestrial.breathe("猪");

Aquatic aquatic = new Aquatic();
aquatic.breathe("鱼");
}


运行结果:


羊生活在陆地上
牛生活在陆地上
猪生活在陆地上
鱼生活在水里

但是问题来了如果这样修改花销是jar是什么意思英语很大的,除了将原来的类分解之外,还需要修改客户端。而直接修改类 Animal 来达成目的虽然违背了单一职责原则,但花销却其他应付款小的多,代码如下:

class Animal{
public void breathe(String animal){
if("鱼".equals(animal)){
System.out.println(animal+"生活在水中");
}else{
System.out.println(animal+"生活在陆地上");
}
}
}


public class Client{
public static void main(String[] args){
Animal animal = new Animal();
animal.breathe("羊");
animal.breathe("牛");
animal.breathe("猪");
animal.breathe("鱼");
}

可以看到,这种修改方式要简单的多。但是却存在着隐患:有一天需要将鱼分为生活在淡水中的鱼和生活在海水的鱼,则又需要修改 Animal 类的 breathe 方法,而对原有代码的修改会对调用“猪”“牛”“羊”等相关功能带来风险,也许某一天你会发现程序运行的结果变为“牛生活在水中”了。

这种修改方式直接在代码级别上违背了单一职责原则,虽然修改起来最系统/运维简单,但隐患却是最大的。还有一种修改方式:

class Animal{
public void breathe(String animal){
System.out.println(animal+"生活在陆地上");
}


public void breathe2(String animal){
System.out.println(animal+"生活在水中");
}
}


public class Client{
public static void main(String[] args){
Animal animal = new Animal();
animal.breathe("牛");
animal.breathe("羊");
animal.breathe("猪");
animal.breathe2("鱼");
}
}

可以看到,这种修改方式没有改动原来的方法,而是在类中新加了一个方法,这样虽然也违背了单一职责原则,但在方法级别上却是符合单一职责原则的,因为它并没有动原来方法jarstick的代码。

单一职责原则三种方式各有优缺点,那么在实际编程中,采系统运维工程师用哪一中呢?其实jars这真的比较难说,需要根据实际情况来确定。我的原则是:只有逻辑足够简单identify,才可以在代码级别上违反单一职责原则;只有类中方法数量足够少,才可以在方法级别上违反idea是什么意思单一职责原则;

例如本文所举的这个例子,它太简单了,它只有一个方法,所以,ide无论是在代码级别上违反单一职责原则,还是在方jar是什么意思法级别上违反,都不会造成太大的影响。实际应用中的类都要复杂的多,一旦发生职责jar扩散而需要修改类时,除非这个类本身非常简单,否则还是遵循单一职责原则的好。

以上就是我所说的单一职责原则了,很多书中介绍的说它并不属于面向对象设计原则中的一种,但是我认为它是,所以我就把他解释出来了。

开放关闭原则

开放关其他业务收入闭原则又称为开放封闭原则。

​定义​​:

一个软件实体应该对扩展开放,对修改关闭,这个原则也是说,系统运维工作内容在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展identify,换句话说,应当可以在不必修改源码的情况下改变这个模块的行为。

这句话其实刚开始看上去是有些矛盾的,接下来在我后边文章解释里面,我会把他解释清楚一点。

我们先用个比较好玩的例子来说一下。

西游记大家都看过,玉帝招安孙悟空的时候的桥段,大家还有没有印象?

当年大闹天宫的时候美猴王对玉皇大帝做了个挑战,美猴王说:皇帝轮流做,明年到我家,只叫他搬出去,将天宫让给我,对于这个挑战,太白金星给玉皇idea安装教程大帝提了个意见,我们把它招上来,给他个小官做,他不就不闹事了?

换一句话说,不用兴师动众的,不破坏天庭的规其他应收款矩这就是闭,但是收他其他应收款是什么科目为官,便是开,招安的其他应收款是什么科目方法便是符合开闭原则的,给他个‘弼马温’的官,便可以ideas让这个系统正常不受威胁,是吧,何idea是什么意思乐而不为?我给大家画个图。

招安的方法的关键就其他业务收入是不允许更改现有的天庭秩其他应付款序,但是idea安装教程允许将妖猴纳入现有的秩序idea是什么意思中,从而扩展了这个秩序,用面向对象的语言来说:不允许更改的是系统的抽象层,而允许扩展的是系统的实ideal现层。

我们写一些简单jared和jensen住一起的代码来进行一个完整的展示来进行一下理解。

​实例​​:

//书店卖书
interface Books{
//书籍名称
public Sting getName();
//书籍价格
public int getPrice();
//书籍作者
public String getAuthor();
}

public class NovelBook implements Books {
private String name;


private int price;


private String author;


public NovelBook(String name, int price, String author) {
this.name = name;
this.price = price;
this.author = author;
}


@Override
public String getName() {
return name;
}


@Override
public int getPrice() {
return price;
}


@Override
public String getAuthor() {
return author;
}
}

以上的代码是数据的实现类和书籍的类别;

下面我们将要开始对书籍进行一个售卖活动:

public class BookStore {
private final static ArrayList<Books> sBookList = new ArrayList<Books>();


static {
sBookList.add(new NovelBook("天龙八部", 4400, "金庸"));
sBookList.add(new NovelBook("射雕英雄传", 7600, "金庸"));
sBookList.add(new NovelBook("钢铁是怎么炼成的", 7500, "保尔柯查金"));
sBookList.add(new NovelBook("红楼梦", 3300, "曹雪芹"));
}


public static void main(String[] args) throws IOException {
NumberFormat format = NumberFormat.getCurrencyInstance();
format.setMaximumFractionDigits(2);
System.out.println("----书店卖出去的书籍记录如下---");
for (Books book : sBookList) {
System.out.println("书籍名称:" + book.getName()
+ "\t书籍作者:" + book.getAuthor()
+ "\t书籍价格:" + format.format(book.getPrice() / 100.00) + "元");
}
}
}

运行结果如下:

D:\develop\JDK8\jdk1.8.0_181\bin\java.exe "-javaagent:D:\develop\IDEA\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=62787:D:\develop\IDEA\IntelliJ IDEA 2018.2.4\bin" -Dfile.encoding=UTF-8 -classpath D:\develop\JDK8\jdk1.8.0_181\jre\lib\charsets.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\deploy.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\dnsns.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\jaccess.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\localedata.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\nashorn.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\sunec.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\zipfs.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\javaws.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\jce.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\jfr.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\jfxswt.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\jsse.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\management-agent.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\plugin.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\resources.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\rt.jar;D:\develop\IDEA_Workspace\CloudCode\out\production\PattemMoudle com.yldyyn.test.BookStore
----书店卖出去的书籍记录如下---
书籍名称:天龙八部 书籍作者:金庸 书籍价格:¥44.00元
书籍名称:射雕英雄传 书籍作者:金庸 书籍价格:¥76.00元
书籍名称:钢铁是怎么炼成的 书籍作者:保尔柯查金 书籍价格:¥75.00元
书籍名称:红楼梦 书籍作者:曹雪芹 书籍价格:¥33.00元


Process finished with exit code 0

但是如果系统运维工程师说现在书店卖jared和jensen住一起书的时候要求打折出售jar,40以上的我们其他综合收益要7折售卖,40以下的我们打8折。

方法有三种,ideal第一个办法:修改接口。在 Bojar包oks 上新增加一个方法 getOnSajargonleideaPrice(),专门进行打折,所有实现类实现这个方法。但是这样修改的后果就是实现类 NovelBook 要修改, BookStore 中的 main 方idea是什么意思法也修系统/运维改,同时 Books 作为接口应该是稳定且可靠的,不应该经常发生变化,否则接口其他应付款做为契约的作用就失去了效能,其他不想打折的书籍也会因为实现了jarstick书籍的接口必须打折,因此该方案被否定。

第二个办法:修改实现类。修改 Novjar是什么意思elBook 类中的方法,直接在 getPrice()jarstick 中实现打折处理,这个应该是大家在项目中经常jarstick使用的就是这样办法,通过 class 文件替换的方式可以完成部分业务(或是缺陷修复)变化,但是该方法还是有缺陷的,例如采购书籍人员也是要idea安装教程看价格的,由于该方法已经实jared和jensen住一起现了打折处理价格,因此采购人员看到的也是打折后的价格,这就产生了信息的蒙蔽效果,导致信息不其他对称而出现决策失误的情况。该方案也不是一个最优的idea方案。

第三个办法,通过扩展实现变化增加一个子类 OffNovelBook,覆写 getPrice 方法,高层次的模块(也就是 static 静态ideology模块区)通过jar是什么意思 OffNovelBjared对jensen独占欲ook 类产生新的对象,完成对业务变化开发任务。好办法,风险也小。

public class OnSaleBook extends NovelBook {


public OnSaleBook(String name, int price, String author) {
super(name, price, author);
}


@Override
public String getName() {
return super.getName();
}


@Override
public int getPrice() {
int OnsalePrice = super.getPrice();
int salePrce = 0;
if (OnsalePrice >4000){
salePrce = OnsalePrice * 70/100;
}else{
salePrce = OnsalePrice * 80/100;
}
return salePrce;
}


@Override
public String getAuthor() {
return super.getAuthor();
}
}

上面的代码是扩展出来的一个类,而不是在原来的类中进系统运维工作内容单一职责原则是从什么演化而来的的修改。

public class BookStore {
private final static ArrayList<Books> sBookList = new ArrayList<Books>();


static {
sBookList.add(new OnSaleBook("天龙八部", 4400, "金庸"));
sBookList.add(new OnSaleBook("射雕英雄传", 7600, "金庸"));
sBookList.add(new OnSaleBook("钢铁是怎么炼成的", 7500, "保尔柯查金"));
sBookList.add(new OnSaleBook("红楼梦", 3300, "曹雪芹"));
}


public static void main(String[] args) throws IOException {
NumberFormat format = NumberFormat.getCurrencyInstance();
format.setMaximumFractionDigits(2);
System.out.println("----书店卖出去的书籍记录如下---");
for (Books book : sBookList) {
System.out.println("书籍名称:" + book.getName()
+ "\t书籍作者:" + book.getAuthor()
+ "\t书籍价格:" + format.format(book.getPrice() / 100.00) + "元");
}
}
}

结果展示:

----书店卖出去的书籍记录如下---
书籍名称:天龙八部 书籍作者:金庸 书籍价格:¥30.80元
书籍名称:射雕英雄传 书籍作者:金庸 书籍价格:¥53.20元
书籍名称:钢铁是怎么炼成的 书籍作者:保尔柯查金 书籍价格:¥52.50元
书籍名称:红楼梦 书籍作者:曹雪芹 书籍价格:¥26.40元


Process finished with exit code 0

在开闭原则中,抽象化是一个关键,解决问题的关键在于抽象化,在 JAVA 语言这种面向对象的语言中,可以给系统定义出一系统运维工资一般多少个一劳永逸的,不再更改的抽象化的设计,此设计允许拥有无穷无尽的实现层被实现。

在 JAVA 语言中,可以给出一个或者多个抽象的 JAVAide0sgrtsts另类 类或者是JAVA接口,规定所有的具体类必须提供方法特征作为系统设计的抽象层,这个抽象层会遇见所有的可能出现的扩展,因此,在任何扩展情况下都不回去改变,这就让系统的抽象层不需要修改,从而满足开闭原则的第二条,对修改进行闭合。

同时,从抽象层里面导出一个或者多个新的具体类可以改变系统的行为,这样就满足了开其他应收款闭原则的第一条。

尽管很多时候我们无法百分百的做到开闭原则,但是如果向着这个方向去努力,就能够有部分的成功,这也是可以改善系统的结构的。

我是懿,一个正在被打击还在努力前进的码农。欢迎大家关注我们的公众号

Java 极客技术公众号,是由一群热爱 Java 开发的技术人组建成立,专注分享原创、高质量的 Java 文章。


                                            设计模式铺铺路(面向对象设计的原则一二)