一. 设计模式概念

        对接口编程而不是对实现编程;优先使用对象组合而不是继承

二. 设计模式总览

1. 创建型模式(Creational Patterns):(5)

单例(Singleton)模式       原型(Prototype)模式        工厂方法(FactoryMethod)模式

抽象工厂(AbstractFactory)模式         建造者(Builder)模式

2. 结构型模式(Structural Patterns): (7)

代理(Proxy)模式        适配器(Adapter)模式        桥接(Bridge)模式

装饰(Decorator)模式        外观(Facade)模式        享元(Flyweight)模式

组合(Composite)模式        过滤器模式(Filter Pattern)

3. 行为型模式(Behavioral Patterns): (11)

模板方法(Template Method)模式        策略(Strategy)模式        命令(Command)模式

职责链(Chain of Responsibility)模式       状态(State)模式        观察者(Observer)模式

中介者(Mediator)模式        迭代器(Iterator)模式        访问者(Visitor)模式

备忘录(Memento)模式        解释器(Interpreter)模式

4. 划分依据

在编写代码时,其实就是对组件(类、接口等)的一系列操作。所以设计模式可以根据组件的生命周期来划分,在组件定义环节如何构建组件就会用到结构型模型;在组件创建环节使用创建型模式;在组件的使用环节可用行为型模式。当然,每个环节并不是独立的,所以各个环节所应用的模式都应该互相考量。

三. 设计模式七大原则

设计模式常用的七大原则有:
                   1)单一职责原则       2)接口隔离原则         3)依赖倒转(倒置)原则      4)里氏替换原则
                   5)开闭原则              6)迪米特法则             7)合成复用原则

1. 单一职责原则

一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。每个类只负责自己的事情,而不是变成万能

代码示例

        以交通工具的使用为例:

方案1,违法单一职责原则

public class SingleResponsibility1 {public static void main(String[] args) {Vehicle vehicle = new Vehicle();vehicle.run("汽车");vehicle.run("摩托");vehicle.run("飞机");}
}
//方案1,违法单一职责原则
class Vehicle{public  void run(String vehicle){System.out.println(vehicle+"在公路上行驶");}
}

方案2,遵守单一职责原则,但是改动很大,要将类分解,且修改客户端

public class SingleResponsibility2 {public static void main(String[] args) {RoadVehicle roadVehice = new RoadVehicle();roadVehice.run("汽车");roadVehice.run("摩托");AirVehicle airVehicle = new AirVehicle();airVehicle.run("飞机");}
}
//方案2,遵守单一职责原则,但是改动很大,要将类分解,且修改客户端
class RoadVehicle{public  void run(String vehicle){System.out.println(vehicle+"在公路上行驶");}
}
class AirVehicle{public  void run(String vehicle){System.out.println(vehicle+"在天空上行驶");}
}

方案3,没有对原来类对大的修改,只是增加方法,虽然没有在类这个级别上遵守单一职责原则,但在方法级别上仍然遵守单一职责原则

public class SingleResponsibility3 {public static void main(String[] args) {Vehicle2 vehicle = new Vehicle2();vehicle.run("汽车");vehicle.run("摩托");vehicle.runAir("飞机");}
}
//方案3,没有对原来类对大的修改,只是增加方法
// 虽然没有在类这个级别上遵守单一职责原则,但在方法级别上仍然遵守单一职责原则
class Vehicle2{public  void run(String vehicle){System.out.println(vehicle+"在公路上行驶");}public  void runAir(String vehicle){System.out.println(vehicle+"在天空上行驶");}
}

2. 接口隔离原则

一个类对另一个类的依赖应该建立在最小的接口上。各个类建立自己的专用接口,而不是建立万能接口

代码示例

        实现下列UML: 类B实现五个方法;类D实现五个方法;类A通过接口Interface1 依赖(使用) B类,但是只会用到1,2,3方法;类C通过接口Interface1 依赖(使用) D类,但是只会用到1,4,5方法

不足:类A通过接口Interface1依赖类B,类C通过接口Interface1依赖类D,如果接口Interface1对于类A和类C来说不是最小接口,那么类B和类D必须去实现他们不需要的方法。

public class Segregation1 {public static void main(String[] args) {Interface1 B = new B();A a = new A();a.depend1(B);a.depend2(B);a.depend3(B);}
}
//接口定义五个方法
interface Interface1{void operation1();void operation2();void operation3();void operation4();void operation5();
}
//类B实现五个方法
class B implements Interface1{@Overridepublic void operation1() {System.out.println("B实现operation1");}@Overridepublic void operation2() {System.out.println("B实现operation2");}@Overridepublic void operation3() {System.out.println("B实现operation3");}@Overridepublic void operation4() {System.out.println("B实现operation4");}@Overridepublic void operation5() {System.out.println("B实现operation5");}
}
//类D实现五个接口
class D implements Interface1{@Overridepublic void operation1() {}@Overridepublic void operation2() {}@Overridepublic void operation3() {}@Overridepublic void operation4() {}@Overridepublic void operation5() {}
}
//类A通过接口Interface1 依赖(使用) B类,但是只会用到1,2,3方法
class A{public void depend1(Interface1 i){i.operation1();}public void depend2(Interface1 i){i.operation2();}public void depend3(Interface1 i){i.operation3();}
}
//类C通过接口Interface1 依赖(使用) D类,但是只会用到1,4,5方法
class C{public void depend1(Interface1 i){i.operation1();}public void depend4(Interface1 i){i.operation4();}public void depend5(Interface1 i){i.operation5();}
}

改进:使用接口隔离原则

public class SegregationImprove {public static void main(String[] args) {A a = new A();a.depend1(new B());a.depend2(new B());a.depend3(new B());}
}//接口1
interface  Interface1{void operation1();
}
//接口2
interface  Interface2{void operation2();void operation3();
}
//接口3
interface  Interface3{void operation4();void operation5();
}//类B实现
class B implements Interface1,Interface2{@Overridepublic void operation1() {System.out.println("B实现operation1");}@Overridepublic void operation2() {System.out.println("B实现operation2");}@Overridepublic void operation3() {System.out.println("B实现operation3");}
}//类D实现
class D implements Interface1,Interface3{@Overridepublic void operation1() {}@Overridepublic void operation4() {}@Overridepublic void operation5() {}
}class A{public void depend1(Interface1 i){i.operation1();}public void depend2(Interface2 i){i.operation2();}public void depend3(Interface2 i){i.operation3();}
}class C{public void depend1(Interface1 i){i.operation1();}public void depend4(Interface3 i){i.operation4();}public void depend5(Interface3 i){i.operation5();}
}

3. 依赖倒转(倒置)原则

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。即面向接口编程,而不是面向实现类

代码示例

        完成Person接受消息功能:方式1,简单比较容易想到,但是如果我们获取的对象是微信等,就要新增类和相应的方法

public class DependenceReversal1 {public static void main(String[] args) {Person person = new Person();person.receive(new Email());person.receive02(new Wechat());}
}
class Email{public String getInfo(){return "电子邮件信息:hello";}
}
//增加微信
class Wechat{public String getInfo(){return "微信信息:hello";}
}
//方式1,简单比较容易想到,但是如果我们获取的对象是微信等,就要新增类和相应的方法
class Person{public void receive(Email email){System.out.println(email.getInfo());}public void receive02(Wechat wechat){System.out.println(wechat.getInfo());}
}

改进:引入一个抽象的接口IReceiver,表示接收者,这样Person类与接口IReceiver发生依赖。因为Email,微信等都属于接收者的范围,各自实现IReceiver,符合依赖倒转原则,无需新增方法

public class DependenceReversal {public static void main(String[] args) {//客户端无需改变Person person = new Person();person.receive(new Email());//新增微信person.receive(new Wechat());}
}
//定义接口
interface IReceiver{public String getInfo();
}
class Email implements IReceiver{public String getInfo(){return "电子邮件信息:hello";}
}
//增加微信
class Wechat implements IReceiver{public String getInfo(){return "微信信息:hello";}
}
//方式2,对接口的依赖
class Person{public void receive(IReceiver receiver){System.out.println(receiver.getInfo());}
}

依赖的3种实现传递的方式

 方式1:通过接口传递实现依赖

public class DependenceReversal {public static void main(String[] args) {ChangHong changHong = new ChangHong();OpenAndClose openAndClose = new OpenAndClose();openAndClose.open(changHong);}
}
//方式1:通过接口传递实现依赖
// 开关接口
interface IOpenAndClose{public void open(ITV itv);
}
//ITV接口
interface ITV{public void play();
}
//长虹电视实现
class ChangHong implements ITV{@Overridepublic void play() {System.out.println("打开长虹电视机");}
}
//实现接口
class OpenAndClose implements IOpenAndClose{@Overridepublic void open(ITV itv) {itv.play();}
}

 方式2:通过构造方法依赖传递

public class DependenceReversal {public static void main(String[] args) {ChangHong2 changHong2 = new ChangHong2();OpenAndClose2 close2 = new OpenAndClose2(changHong2);close2.open();}
}
//方式2:通过构造方法依赖传递
interface IOpenAndClose2{public void open();
}
interface ITV2{public void play();
}
//长虹电视实现
class ChangHong2 implements ITV2{@Overridepublic void play() {System.out.println("打开长虹电视机");}
}
class OpenAndClose2 implements IOpenAndClose2{public ITV2 itv;public OpenAndClose2(ITV2 itv){this.itv = itv;}@Overridepublic void open() {this.itv.play();}
}

        方式3:通过setter方法传递 

public class DependenceReversal {public static void main(String[] args) {    ChangHong3 changHong3 = new ChangHong3();OpenAndClose3 close3 = new OpenAndClose3();close3.setTv(changHong3);close3.open();}
}
//方式3:通过setter方法传递
interface IOpenAndClose3{public void open();public void setTv(ITV3 tv);
}
interface ITV3{public void play();
}
//长虹电视实现
class ChangHong3 implements ITV3{@Overridepublic void play() {System.out.println("打开长虹电视机");}
}
class OpenAndClose3 implements IOpenAndClose3{public ITV3 itv;@Overridepublic void open() {this.itv.play();}@Overridepublic void setTv(ITV3 tv) {this.itv = tv;}
}

4. 里氏替换原则

继承必须确保超类所拥有的性质在子类中仍然成立。即继承父类而不去改变父类

代码示例

        B类继承A类,增加一个新功能:两数相加,但是误将A类方法1重写,导致错误

//A类
class A{//返回两数之差public int func1(int num1,int num2){return num1-num2;}
}
//B类继承A类,增加一个新功能:两数相加,但是误将A类方法1重写,导致错误
class B extends A{public int func1(int a,int b){return a+b;}public int func2(int a,int b){return func1(a,b)+9;}
}

改进:创建一个更加基础的基类,把更加基础的方法和成员写在基类中,B类,如果需要使用A类方法,可采用组合方式

//创建一个更加基础的基类
class Base{//把更加基础的方法和成员写在基类中
}
//A类
class A extends Base{//返回两数之差public int func1(int num1,int num2){return num1-num2;}
}
//B类,如果需要使用A类方法,可采用组合方式
class B extends Base{private A al = new A();public int func2(int a,int b){return al.func1(a,b)+9;}
}

5. 开闭原则

软件实体应当对扩展开放,对修改关闭即扩展新类而不是修改旧类

(合成复用原则、里氏替换原则相辅相成,都是开闭原则的具体实现规范)

代码示例

        以绘图为例,根据m_type不同调用不同方法绘制不同图形,优点是比较好理解,简单易操作。缺点是违反了设计模式的ocp原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码。比如我们这时要新增加一个图形种类,我们需要修改很多地方(创建新类,增加方法,增加判断)。

public class OpenAndClose {public static void main(String[] args) {GraphicEditor editor = new GraphicEditor();editor.drawShape(new Circle());editor.drawShape(new Rectangle());}
}
class GraphicEditor{public void drawShape(Shape s){if(s.m_type == 1){drawRectangle(s);}else {drawCircle(s);}}public void drawRectangle(Shape r){System.out.println("矩形");}public void drawCircle(Shape r){System.out.println("圆形");}
}
class Shape{int m_type;
}
class Rectangle extends Shape{Rectangle(){super.m_type = 1;}
}
class Circle extends Shape{Circle(){super.m_type = 2;}
}

改进:把Shape类做成抽象类,并提供一个抽象的draw方法,让子类去实现,这样我们有新的图形种类时,只需要让新的图形类继承Shape,并实现draw方法即可,使用方的代码就不需要修改,满足了开闭原则。

public class OpenAndClose {public static void main(String[] args) {GraphicEditor editor = new GraphicEditor();editor.drawShape(new Circle());editor.drawShape(new Rectangle());}
}
class GraphicEditor{public void drawShape(Shape s){s.draw();}
}
abstract class Shape{public abstract void draw();
}
class Rectangle extends Shape{@Overridepublic void draw() {System.out.println("绘制矩形");}
}
class Circle extends Shape{@Overridepublic void draw() {System.out.println("绘制圆形");}
}

6. 迪米特法则

最少知识原则,只与你的直接朋友交谈,不跟“陌生人”说话。即无需直接交互的两个类,如果需要交互,使用中间者

        直接朋友: 每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部

代码示例

以学院和学校为例,打印出所有员工。分析SchoolManager直接朋友是Employee,CollegeManager,但是CollegeEmployee不是直接朋友而是以局部变量的方式出现在类内部,违法了迪米特法则

public class Dimilit {public static void main(String[] args) {SchoolManager schoolManager = new SchoolManager();schoolManager.printAllEmployee(new CollegeManager());}
}//学校总部员工类
class Employee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}
//学院员工类
class CollegeEmployee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}
//管理学院类
class CollegeManager{//返回学院员工public List<CollegeEmployee> getAllEmployee(){List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();for (int i = 0; i < 10; i++) {CollegeEmployee emp = new CollegeEmployee();emp.setId("学院员工id= "+i);list.add(emp);}return list;}
}
//管理学校类
class SchoolManager{//返回学校总部员工public List<Employee> getAllEmployee(){List<Employee> list = new ArrayList<Employee>();for (int i = 0; i < 5; i++) {Employee emp = new Employee();emp.setId("学院员工id= "+i);list.add(emp);}return list;}//打印所有员工void printAllEmployee(CollegeManager collegeManager){List<CollegeEmployee> list1 = collegeManager.getAllEmployee();System.out.println("------------学院员工-------------");for (CollegeEmployee collegeEmployee : list1) {System.out.println(collegeEmployee.getId());}List<Employee> list2 = this.getAllEmployee();System.out.println("------------总部员工-------------");for (Employee employee : list2) {System.out.println(employee.getId());}}
}

改进:将输出学院的员工方法,封装到CollegeManager

public class Dimilit {public static void main(String[] args) {SchoolManager schoolManager = new SchoolManager();schoolManager.printAllEmployee(new CollegeManager());}
}//学校总部员工类
class Employee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}//学院员工类
class CollegeEmployee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}//管理学院类
class CollegeManager{//返回学院员工public List<CollegeEmployee> getAllEmployee(){List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();for (int i = 0; i < 10; i++) {CollegeEmployee emp = new CollegeEmployee();emp.setId("学院员工id= "+i);list.add(emp);}return list;}//输出学院员工信息public void printEmployee(){List<CollegeEmployee> list1 = getAllEmployee();System.out.println("------------学院员工-------------");for (CollegeEmployee collegeEmployee : list1) {System.out.println(collegeEmployee.getId());}}
}//管理学校类
class SchoolManager{//返回学校总部员工public List<Employee> getAllEmployee(){List<Employee> list = new ArrayList<Employee>();for (int i = 0; i < 5; i++) {Employee emp = new Employee();emp.setId("学院员工id= "+i);list.add(emp);}return list;}//打印所有员工void printAllEmployee(CollegeManager collegeManager){//输出学院员工collegeManager.printEmployee();//输出学校员工List<Employee> list2 = this.getAllEmployee();System.out.println("------------总部员工-------------");for (Employee employee : list2) {System.out.println(employee.getId());}}
}

7. 合成复用原则

软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。即优先组合,其次继承

        代码示例

        Head类与Person类同生死,组合关系;IDCard类与Person,聚合关系

class Person {private IDCard card; //聚合关系private Head head = new Head(); //组合关系
}
class IDCard {}
class Head {}

四.设计模式核心思想

1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一 起

2. 针对接口编程,而不是针对实现编程

3. 为了交互对象之间的松耦合设计而努力

设计模式——七大原则(附代码示例)相关推荐

  1. C语言和设计模式大全(附代码示例)

    文章目录 C语言和设计模式(之单件模式) C语言和设计模式(之原型模式) C语言和设计模式(之组合模式) C语言和设计模式(之模板模式) C语言和设计模式(工厂模式) C语言和设计模式(责任链模式) ...

  2. 设计模式——七大原则

    设计模式--七大原则 汇总篇 1.单一职责 2.接口隔离 3.依赖倒转 4.里氏代换原则 5.开闭原则 6.迪米特法则 7.合成复用 汇总篇 1.单一职责 对类来说的,即一个类应该只负责一项职责.如类 ...

  3. 备战面试日记(3.1) - (设计模式.七大原则)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.4 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...

  4. Java面试之设计模式七大原则

    最近项目不太忙,不怎么加班,正利用晚上时间好好学习学习设计模式,之前可能多多少少都用到过,但是有些还是很模糊,这下正好系统的学一下. 好了,话不多说,进入正题. 1.什么是设计模式? 软件工程中,设计 ...

  5. 第 2 章 设计模式七大原则

    第 2 章 设计模式七大原则 1.设计模式的目的 编写软件过程中,程序员面临着来自 耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性 等多方面的挑战, 设计模式是为了让程序(软件),具有如下更好的 ...

  6. 图解设计模式-设计模式七大原则

    Java设计模式 设计模式七大原则 设计模式的目的 编写软件过程中,程序员面临来自 耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性等多方面的挑战,设计模式是为了让 **程序(软件)**具有更好的 ...

  7. Day305.设计模式七大原则 -Java设计模式

    七大设计原则 一.设计模式的目的 编写软件过程中,程序员面临着来自 耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性 等多方面的挑战,设计模式是为了让程序(软件),具有更好的↓↓↓ 1. 代码重用 ...

  8. Java设计模式七大原则-单一职责原则

    目录 概述:设计模式的目的 设计模式七大原则 单一职责原则 单一职责原则注意事项和细节 概述:设计模式的目的 编写软件过程中,程序员面临着来自 耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性 等 ...

  9. 设计模式七大原则介绍

    文章目录 1. 设计模式有哪些种类 2. 设计模式的目的 3. 设计模式七大原则 3.1. 单一职责原则 1. 基本介绍 2. 模拟场景 2. 接口隔离原则 1. 基本介绍 2. 模拟场景 3. 依赖 ...

最新文章

  1. WKWebView 实现iOS与H5的交互转
  2. Entity Framework快速入门笔记第四篇—ModelFirst
  3. shell中的条件表达式
  4. cpu高对计算机有什么影响吗,CPU损坏对电脑造成哪些影响
  5. WordPress 常用数据库SQL查询语句大全
  6. snort 使用mysql的安装
  7. Ubuntu系统下ntp服务器搭建
  8. eclipse中配置server
  9. CentOS 7 重装mysql编译过程报错解决方法
  10. 防火墙双机热备配置实例(二)
  11. 第四章 数字调制方式
  12. java字符常量_java字符常量
  13. 破解qq上网限制 突破限制上QQ
  14. vue 创建项目之vue init webpack xxx
  15. 数字信号处理 实验一 时域采样与频域采样【实验报告】
  16. mysql like 原理_MySql原理
  17. 禁止Win系统自动唤醒
  18. 计算机提示无法识别usb,小编教你电脑出现无法识别usb设备怎么办
  19. 睿爸信奥-【临阵磨枪】练习赛(第二场)- T2
  20. python django 安装虚拟环境创建工程项目

热门文章

  1. android studio模拟器出错,A resource failed to call close
  2. Java、JSP大阳电动车销售系统的设计与实现
  3. 谷歌将发布全新搜索引擎,你期待吗?
  4. 亿图图示----组织架构图----市场组织架构和公司架构图及家庭架构图
  5. 【附源码】计算机毕业设计JAVA网上鲜花店系统
  6. 853. 有边数限制的最短路(bellman_ford算法)
  7. 清北学堂培训2019.4.6
  8. 我学炒外汇 第十三篇影响瑞士法郎的因素
  9. mysql 索引代码_mysql索引
  10. Win10桌面图标显示不正常变成了白色