前言
去年的11月份吧,我考下了中级软件设计师的证书,里面的必考题之一就是设计模式,虽然也没有很难考,但是如果你是要去国企工作的读者,其实我建议还是考上一考,一方面是对知识的复习,另一方面就是多少加一点工资。
以下附上一个报名的链接:http://bm.ruankao.org.cn/sign/welcome
思维导图
六大原则
文章结构:定义 ---> 白话
单一职责原则
定义:就一个类而言,应该仅有一个引起它变化的原因。
其实字面意思就已经表达的比较明确,单一
,也就是干尽量少的事情。在HDU中可以对耦合和内聚程度的评判有一定的了解。
什么叫做少,其实很难有一个标准。但是在Android的MVC框架中,Activity既作为View,又起着Controller的作用的时候是否显得会很臃肿呢?他需要进行页面的刷新,网络处理,消息处理等等,写起来容易,但是在我们进行维护的时候,是不是会很头疼呢。
开放封闭原则
定义:类,模块,函数等应该是可以扩展的,但是不可以修改。
在日常的项目开发中,需求一直是处于一个变动的状态,但是这同样也会成为项目开发的壁垒,如果你的Bean
今天是一只猫,明天就需要是一只狗呢?重新打补丁吗?显然是一个很不合适的做法。而开放封闭原则,解决的就是这一类问题。不论是猫,还是狗,他们总会有相同的特征,抽象化也就是这个原则实现的基础。
// 定义一个动物抽象类 public abstract class Animal { abstract void do(); } // 猫实现抽象方法 class Cat extends Animal { @Override void do() { System.out.println("喵"); } } // 狗实现抽象方法 class Dog extends Animal { @Override void do() { System.out.println("汪"); } }
里氏替换原则
定义:所有引用基类(一般来说都是抽象类或接口)的地方必须能透明的使用其子类的对象。
定义的具体含义就是将一个基类对象替换成其子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。
或者你还是不理解的话,以下两段代码,就很清晰的解析了上述的含义。
List list = new ArrayList<String>(); ArrayList list = new List<String>();
ArrayList
作为我们撸代码日子里的亲人,你见过第二种写法吗?
接下来就是里氏替换原则的具体实现了。
/** * 基于里氏替换原则实现 */ class Manage1 { private Animal animal; public void setAnimal(Animal animal) { this.animal = animal; } void getSound() { animal.do(); } } /** * 使用子类实现 */ class Manage2 { private Cat cat; public void setAnimal(Cat cat) { this.cat = cat; } void getSound() { cat.do(); } }
以上基于两种写法,给予读者评判,如果使用Manage2
,如果我们希望获得Dog
的声音,那么就需要重新实现Manager3
,然后差异就是只是把Cat
置换成Dog
。而Manage1
很好的解决了这个问题,因为不论是Cat
还是Dog
都是Animal
的子类。
依赖倒置原则
定义:高层模块不应该依赖底层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
两个概念:
- 抽象/高层模块:接口或者抽象类,一般只定义了有什么操作,但是没有具体实现。
- 细节/底层模块:实现接口或者继承抽象类而产生的,一般来说就是new出来的对象。
这里的代码与里氏替换原则一致。
迪米特原则
定义:一个软件实体应当少的与其他实体发生相互作用。
其实和上面的内容差不多,同样都是为了降低耦合程度,直接用Demo证明就清楚明了了。
电话网络形式
- 打电话的人 --> 接电话的人
- 打电话的人 --> 中间服务商转接 --> 接电话的人
第一种已经被时代抛弃了,虽然我们并不知觉,但是第一种电话网络模式,如果用在现代社会,那么带来的后果就是你再也看不见太阳了,头顶密密麻麻的电话线,更何况那是座机互联的时代,能够靠电话线来解决,但是这个时代呢?移动互联的时代呢,不能再靠着电话线来解决问题,而是中间商的介入就改变了这个现状。
第一种电话网络模式
/** * 打电话的人 */ class Call { private Receiver receiver; public void setReceicer(Receiver receiver) { this.receiver = receiver; } public void call() { receiver.receive(); } } /** * 接电话的人 */ class Receiver{ private String number; Receiver(String number){ this.number = number; } public void receive() { System.out.println("接通电话"); } } class Main{ public static void main(String[] args) { Call call = new Call(); call.setReceicer(new Receiver("电话号码")); call.call(); } }
第二种电话网络模式
/** * 转接 */ public abstract class Manager { abstract void link(); } /** * 打电话的人 */ class Call { private Manager manager; public void setManager(Manager manager) { this.manager = manager; } public void call() { manager.link(); } } /** * 接电话的人 */ class Receiver{ private String number; Receiver(String number){ this.number = number; } public void receive() { System.out.println("接通电话"); } } class CMCC extends Manager { private String number; CMCC(String number){ this.number = number; } public void link() { System.out.println("连接接电话的人"); Receiver receiver = new Receiver(); receiver.receive(); } } class Main{ public static void main(String[] args) { Call call = new Call(); call.setManager(new CMCC("电话号码")); call.call(); } }
这个时候两个实体通过加入中间商的形式降低了耦合度。
接口隔离原则
定义:一个类对另一个类的依赖应该建立在最小的接口上
一个接口内要实现的函数数量可控,有那么一点像数据库里的第一范式。让我们从Demo看看使用原则的与否的不同之处。
正常实现
// 特征 interface Character { void look(); void nature(); } class Dog implements Character{ @Override void look() { System.out.println("能看"); } @Override void nature() { System.out.println("淘气"); } }
基于接口隔离原则实现
// 外观 interface Facade { void look(); } // 内在 interface Inherent { void nature(); } class Dog implements Inherent{ @Override void nature() { System.out.println("淘气"); } }
总结
七大原则其实表明的意思还是比较明确的,虽然可能写法上的难度会有一定的增加,但是如果使用得当,后期的维护成本将会大大降低。