设计模式

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案

https://www.zhihu.com/question/305042684
面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。

OOP是组件化思想的一种体现,把对象作为程序的基本单元,将对象作为一个封装好的“积木”,屏蔽内部复杂性,对外暴露接口。与其他对象相互合作搭成一个程序。

二、AOP面向切面编程
也是一种编程思想,面对对象思想的一种补充,为分散的对象引入公共行为,植入增强代码,如给多个对象加事务和日志处理。主要是通过动态代理的方式实现。

接口

  1. java中的接口就是一种公共规范标准,对外部约定的契约,定义接口就是在描述规范,实现接口就是在实现规范
  • 接口是对类的行为的抽象,如人有打乒乓球,羽毛球等行为可以抽象为一个运动接口
  • 抽象类是对类本身的抽象,接口是对类类行为的抽象,继承是不是,实现有没有。
    抽象找相同,实现找不同。


定义:一种设计思想
在代码中体现:
在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。

DIP原则
从业务角度来说
面向接口编程就是先把客户的业务提取出来,作为接口。业务具体实现通过该接口的实现类来完成。当客户需求变化时,只需编写该业务逻辑的新的实现类,通过更改配置文件(例如Spring框架)中该接口的实现类就可以完成需求,不需要改写现有代码,减少对系统的影响

ico和di ioc是目的,di是手段。ioc是指让生成对象的方式由传统方式(new)反过来,既程序员不调用new,需要类的时候由框架注入(di),是同一件不同层面的解读

一、IoC控制反转(IoC,Inversion of Control)

是一种编程思想。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。把对象的创建、初始化、销毁等工作交给spring容器来做。由spring容器控制对象的生命周期。即是将new 的过程交给spring容器去处理

例如:早上去早餐店买了一个包子,包子是早餐店做的,你通过钱买下了包子,包子的决定权就从早餐店转移到了你的手上。

二、DI依赖注入

依赖注入DI是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。依赖注入是目前最优秀的解耦方式。依赖注入让Spring的Bean之间以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起的。

  1. 控制反转(IoC)实际上是一种设计思想,一种软件设计目的,将类的依赖的控制权转移到第三方,如IOC容器,由第三方容器负责依赖对象的创建,初始化和注入。DI依赖注入,是一种手段,实现注入的一种手段。**DI是实现的IOC的一种手段**。例如想达到活着的目的你就要吃饭、喝水,你可以吃面条活着,也可以吃饭活着,活着就是你的目的,达到这个目的你要必须要吃,喝。DI是一种手段可以理解为吃饭,通过吃饭来达到活着的目的<br />![2021-02-03_220950.png](https://cdn.nlark.com/yuque/0/2021/png/12466223/1612361446573-daf5a4b7-8436-4f8e-8220-9bff0a9fce2d.png#height=558&id=k4joL&margin=%5Bobject%20Object%5D&name=2021-02-03_220950.png&originHeight=558&originWidth=1075&originalType=binary&ratio=1&size=16903&status=done&style=none&width=1075)

1、设计原则

1.1 开闭原则

定义

对拓展开放,对修改关闭。用抽象设计框架,用拓展实现细节

栗子一枚:

  1. /**
  2. * 开闭原则 加拓展 不修改底层
  3. *
  4. * 如此时 有个课程打折的需求 此时该怎么做 ?
  5. *
  6. * 修改接口和修改JavaCourse这种偏底层的类或接口都可能导致其他问题,此时可以加拓展
  7. *
  8. * 此时该定义一个类继承JavaCourse类复写getPrice方法
  9. *
  10. *
  11. */
  12. public class JavaCourse implements ICourse {
  13. private String name;
  14. private Integer id;
  15. private double price;
  16. public JavaCourse(String name, Integer id, double price) {
  17. this.name = name;
  18. this.id = id;
  19. this.price = price;
  20. }
  21. @Override
  22. public String getName() {
  23. return name;
  24. }
  25. @Override
  26. public Integer getId() {
  27. return id;
  28. }
  29. @Override
  30. public double getPrice() {
  31. return price;
  32. }
  33. @Override
  34. public String toString() {
  35. return "JavaCourse{" +
  36. "name='" + getName() + '\'' +
  37. ", id=" + getId() +
  38. ", price=" + getPrice() +
  39. '}';
  40. }
  41. }
  42. package com.lilei.design.principle.closeopen;
  43. public class JavaDiscountCount extends JavaCourse {
  44. public JavaDiscountCount(String name, Integer id, double price) {
  45. super(name, id, price);
  46. }
  47. @Override
  48. public double getPrice() {
  49. return super.getPrice()*0.8;
  50. }
  51. @Override
  52. public String toString() {
  53. return "JavaDiscountCount{}"+super.toString();
  54. }
  55. }

1.2 依赖倒置原则

定义

1.高层模块不应该依赖底层模块,二者都应该依赖其抽象

2.抽象不依赖细节;细节应该依赖抽象

3.针对接口编程,不要针对实现编程

上面定义不难理解,主要包含两次意思:

1)高层模块不应该直接依赖于底层模块的具体实现,而应该依赖于底层的抽象。换言之,模块间的依赖是通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。

2)接口和抽象类不应该依赖于实现类,而实现类依赖接口或抽象类。这一点其实不用多说,很好理解,“面向接口编程”思想正是这点的最好体现。

减少耦合

栗子一枚 Studyer并不直接依赖 JavaCourse PhpCourse这个两个底层类而是依赖其抽象

  1. package com.lilei.design.principle.dependenceinversion;
  2. public class Studyer {
  3. public void studyCourse(ICourse iCourse){
  4. iCourse.studyCourse();
  5. }
  6. /* public void studyJava(){
  7. System.out.println("studying java");
  8. }
  9. public void studyPhp(){
  10. System.out.println("studying php");
  11. }*/
  12. }

1.3单一职责原则

定义

1、不要存在多于一个倒置类变更的原因

2、一个类/接口/方法 只负责一项职责

优点,降低类的复杂度,提高类的可读性

  1. 方法的单一职责
  1. package com.lilei.design.principle.singleresponsibility;
  2. public class Work {
  3. //当出现这种情况则应该将其拆分为两个方法
  4. public void demoSingle(boolean bool){
  5. if (bool) {
  6. //todo something
  7. }
  8. else{
  9. //todo something
  10. }
  11. }
  12. }
  1. package com.lilei.design.principle.singleresponsibility;
  2. public interface ICourse {
  3. // 当这个接口有两个职责时,则应该将其拆为两个接口
  4. void manageCourse();
  5. void studyCourse();
  6. }

1.4接口隔离原则

定义:

用多个专门的接口而不是使用单一的总接口,客户端不应该依赖他不需要的接口

1.一个类对一个类的依赖应该建立在最小的接口上

2.建立单一接口,不要庞大的接口

3.尽量细化接口,接口中的方法尽量少

栗子一枚

  1. package com.lilei.design.principle.interfacesegregation;
  2. public interface IAnimalAction {
  3. void eat();
  4. void swim();
  5. void fly();
  6. }
  1. package com.lilei.design.principle.interfacesegregation;
  2. /**
  3. dog实现IAnimalAction接口但dog并不具备fly这个行为,所以这个就是一个空实现
  4. 在设计接口时要 尽量细化接口 保证准确性
  5. */
  6. public class Dog implements IAnimalAction {
  7. @Override
  8. public void eat() {
  9. }
  10. @Override
  11. public void swim() {
  12. }
  13. @Override
  14. public void fly() {
  15. }
  16. }

1.5最少知道原则

定义:一个对象应该对其他对象保持最少的了解

  1. 尽量降低类的耦合

强调只和朋友交流,不和陌生人说话

朋友:出现在成员变量,方法的入参和出参的类称为朋友类,而出现在方法体内部的类不视为朋友类

  1. package com.lilei.design.principle.demeter;
  2. import java.util.ArrayList;
  3. public class Boss {
  4. public void commandTeamLeader(TeamLeader teamLeader){
  5. teamLeader.selectCourse();
  6. }
  7. }
  1. package com.lilei.design.principle.demeter;
  2. import java.util.ArrayList;
  3. public class TeamLeader {
  4. public void selectCourse() {
  5. ArrayList<Course> list = new ArrayList<Course>();
  6. for (int i = 0; i < 20; i++) {
  7. list.add(new Course());
  8. }
  9. System.out.println(list.size());
  10. }
  11. }

核心就是区分出朋友

2、创建模式

工厂模式

  • 工厂模式模式一种创建对象的模式,它被广泛应用在jdk中以及Spring和Struts框架中;

1.简单工厂

由工厂对象决定创建哪一种对象,只要一个简单的参数

  1. package com.lilei.design.pattern.creational.simplefactory;
  2. public class VideoFactory {
  3. public Video makeVideo(Class<? extends Video> video){
  4. try {
  5. return video.newInstance();
  6. } catch (InstantiationException | IllegalAccessException e) {
  7. e.printStackTrace();
  8. }
  9. return null;
  10. }
  11. }

2.工厂方法

定义
工厂方法模式基于”输入”,应用在超类和多个子类之间的情况,这种模式将创建对象的责任转移到工厂类;

定义:一个创建类的接口但让实现这个接口的类来决定实现那个类,工厂方法让类的实例化推迟到子类中进行

  1. package com.lilei.design.pattern.creational.factorymethod;
  2. public abstract class VideoFactory {
  3. // 类的实例化,推迟到子类来实现
  4. abstract Video makeVideo();
  5. }
  1. package com.lilei.design.pattern.creational.factorymethod;
  2. public class PhpVideoFactory extends VideoFactory {
  3. @Override
  4. Video makeVideo() {
  5. return new PhpVideo();
  6. }
  7. }
  1. package com.lilei.design.pattern.creational.factorymethod;
  2. public class JavaVideoFactory extends VideoFactory {
  3. @Override
  4. Video makeVideo() {
  5. return new JavaVideo();
  6. }
  7. }
  8. //===========================创建对象==============================
  9. package com.lilei.design.pattern.creational.factorymethod;
  10. public class Test {
  11. public static void main(String[] args){
  12. VideoFactory videoFactory = new JavaVideoFactory();
  13. Video video = videoFactory.makeVideo();
  14. video.play();
  15. }
  16. }

当有新的类(和已知类处于同一产品等级)要被实例化时不用修改类,而是使用新加工厂的方式来创建,符合开闭原则,到也可能会导致类的数量过多
2020-11-08_092727.png
适用环境

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
  • loger.jpg

例子

  1. package java.lang;
  2. import java.util.Iterator;
  3. import java.util.Objects;
  4. import java.util.Spliterator;
  5. import java.util.Spliterators;
  6. import java.util.function.Consumer;
  7. /**
  8. * Implementing this interface allows an object to be the target of the enhanced
  9. * {@code for} statement (sometimes called the "for-each loop" statement).
  10. *
  11. * @param <T> the type of elements returned by the iterator
  12. *
  13. * @since 1.5
  14. * @jls 14.14.2 The enhanced {@code for} statement
  15. */
  16. public interface Iterable<T> {
  17. Iterator<T> iterator();
  18. }

Iterable接口可以视为一个工厂方法的接口申明一个创建iterator实例的方法 由实现类 ArrayList负责真正创建该实例
2021-02-04_160213.png

  1. ArrayList
  2. public Iterator<E> iterator() {
  3. return new Itr();
  4. }
  5. private class Itr implements Iterator<E> {
  6. /**
  7. * Index of element to be returned by subsequent call to next.
  8. */
  9. int cursor = 0;
  10. /**
  11. * Index of element returned by most recent call to next or
  12. * previous. Reset to -1 if this element is deleted by a call
  13. * to remove.
  14. */
  15. int lastRet = -1;
  16. /**
  17. * The modCount value that the iterator believes that the backing
  18. * List should have. If this expectation is violated, the iterator
  19. * has detected concurrent modification.
  20. */
  21. int expectedModCount = modCount;
  22. public boolean hasNext() {
  23. return cursor != size();
  24. }
  25. public E next() {
  26. checkForComodification();
  27. try {
  28. int i = cursor;
  29. E next = get(i);
  30. lastRet = i;
  31. cursor = i + 1;
  32. return next;
  33. } catch (IndexOutOfBoundsException e) {
  34. checkForComodification();
  35. throw new NoSuchElementException();
  36. }
  37. }
  38. public void remove() {
  39. if (lastRet < 0)
  40. throw new IllegalStateException();
  41. checkForComodification();
  42. try {
  43. AbstractList.this.remove(lastRet);
  44. if (lastRet < cursor)
  45. cursor--;
  46. lastRet = -1;
  47. expectedModCount = modCount;
  48. } catch (IndexOutOfBoundsException e) {
  49. throw new ConcurrentModificationException();
  50. }
  51. }
  52. final void checkForComodification() {
  53. if (modCount != expectedModCount)
  54. throw new ConcurrentModificationException();
  55. }
  56. }java

抽象工厂模式

2021-02-04_165852.png
3E13CDD1-2CD2-4C66-BD33-DECBF172AE03.jpg
1、工厂方法中的工厂只生产同一产品等级的生产
2、抽象工厂的生产同一产品族中的产品

建造者模式

定义:将一个复杂对象的建造和它的表示分离,使得同样的建造过程有不同的表示

  1. 用户只需指定需要建造的类型就可以得到它们,建造过程及细节不需要知道

适用场景 一个类有很多属性,把复杂的对象的创建和使用分离
复杂对象相当于一辆有待建造的汽车,而对象的属性相当于汽车的部件,建造产品的过程就相当于组合部件的过程。由于组合部件的过程很复杂,因此,这些部件的组合过程往往被“外部化”到一个称作建造者的对象里,建造者返还给客户端的是一个已经建造完毕的完整产品对象,而用户无须关心该对象所包含的属性以及它们的组装方式,这就是建造者模式的模式动机。

  1. package com.lilei.design.pattern.creational.builder.v2;
  2. public class Course {
  3. private String courseName;
  4. private String ppt;
  5. private String courseVideo;
  6. private String article;
  7. private String QA;
  8. public Course(CourseBuilder courseBuilder) {
  9. this.courseName = courseBuilder.courseName;
  10. this.ppt = courseBuilder.ppt;
  11. this.courseVideo = courseBuilder.courseVideo;
  12. this.article = courseBuilder.article;
  13. this.QA = courseBuilder.QA;
  14. }
  15. @Override
  16. public String toString() {
  17. return "Course{" +
  18. "courseName='" + courseName + '\'' +
  19. ", ppt='" + ppt + '\'' +
  20. ", courseVideo='" + courseVideo + '\'' +
  21. ", article='" + article + '\'' +
  22. ", QA='" + QA + '\'' +
  23. '}';
  24. }
  25. public static class CourseBuilder{
  26. private String courseName;
  27. private String ppt;
  28. private String courseVideo;
  29. private String article;
  30. private String QA;
  31. public CourseBuilder buildCourseName(String courseName) {
  32. this.courseName = courseName;
  33. return this;
  34. }
  35. public CourseBuilder buildPpt(String ppt) {
  36. this.ppt = ppt;
  37. return this;
  38. }
  39. public CourseBuilder buildCourseVideo(String courseVideo) {
  40. this.courseVideo = courseVideo;
  41. return this;
  42. }
  43. public CourseBuilder buildArticle(String article) {
  44. this.article = article;
  45. return this;
  46. }
  47. public CourseBuilder buildQA(String QA) {
  48. this.QA = QA;
  49. return this;
  50. }
  51. public Course build(){
  52. return new Course(this);
  53. }
  54. }
  55. }

单例模式

有线程安全问题

  1. package com.lilei.design.pattern.creational.singleinstance;
  2. public class LazySingleton {
  3. private static LazySingleton lazySingleton = null;
  4. private LazySingleton() {
  5. }
  6. public static LazySingleton getInstance(){
  7. if (lazySingleton == null){
  8. lazySingleton = new LazySingleton();
  9. }
  10. return lazySingleton;
  11. }
  12. }

补充一个多线程调试的方法

1、右击断点,选择thread

2、在frame下选择thread

运行线程单击run

单例模式 双重检查锁

  1. package com.lilei.design.pattern.creational.singleinstance;
  2. /**
  3. * 双重检查锁 在性能和安全之间平衡
  4. */
  5. class LazyDoubleCheckSingleton {
  6. private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
  7. private LazyDoubleCheckSingleton() {
  8. }
  9. public static LazyDoubleCheckSingleton getInstance(){
  10. if (lazyDoubleCheckSingleton == null){
  11. //只锁住一小部分代码
  12. synchronized (LazyDoubleCheckSingleton.class){
  13. if (lazyDoubleCheckSingleton ==null)
  14. lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
  15. }
  16. }
  17. return lazyDoubleCheckSingleton;
  18. }
  19. }

2.对象创建的排序问题

lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); 对象创建还没有完全完成

但lazyDoubleCheckSingleton已经指向了内存空间,此时访问对象会造成隐患

原型模式

指原型实例指定创建对象的种类,通过拷贝这些原型创建新的对象

  1. 适用场景

1、类初始化消耗过多资源

2、new 对象需要非常繁琐

3、构造函数非常复杂

4、循环中产生大量对象

即使用克隆来创建复杂对象

  1. package com.lilei.design.pattern.prototype;
  2. public class Mail implements Cloneable {
  3. private String username;
  4. private String address;
  5. private String content;
  6. public String getUsername() {
  7. return username;
  8. }
  9. public void setUsername(String username) {
  10. this.username = username;
  11. }
  12. public String getAddress() {
  13. return address;
  14. }
  15. public void setAddress(String address) {
  16. this.address = address;
  17. }
  18. public String getContent() {
  19. return content;
  20. }
  21. public void setContent(String content) {
  22. this.content = content;
  23. }
  24. @Override
  25. protected Object clone() throws CloneNotSupportedException {
  26. return super.clone();
  27. }
  28. @Override
  29. public String toString() {
  30. return "Mail{" +
  31. "username='" + username + '\'' +
  32. ", address='" + address + '\'' +
  33. '}';
  34. }
  35. }

深拷贝和浅拷贝

  1. package com.lilei.design.pattern.prototype.deepcopy;
  2. import java.util.Date;
  3. public class Test {
  4. public static void main(String[] args) throws CloneNotSupportedException {
  5. Pig pig = new Pig("佩奇", new Date(0));
  6. Pig pig1 = (Pig) pig.clone();
  7. /* pig.setBirthday(new Date(1112121));
  8. * Pig{name='佩奇', birthday=Thu Jan 01 08:18:32 CST 1970}com.lilei.design.pattern.prototype.deepcopy.Pig@511baa65
  9. Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.lilei.design.pattern.prototype.deepcopy.Pig@28feb3fa
  10. * 这种写法pig中的birthday会赋值为一个新的引用,指向新的内存
  11. * */
  12. //这种修改pig.birthday引用指向的内存中的东西 但两个对象还是拥有同一个引用 所以都会被修改
  13. //解决办法就是 将 pig.birthday 再克隆一下
  14. pig.getBirthday().setTime(111111111);
  15. System.out.println(pig);
  16. System.out.println(pig1);
  17. }
  18. }
  1. package com.lilei.design.pattern.prototype.deepcopy;
  2. import java.util.Date;
  3. public class Pig implements Cloneable {
  4. String name;
  5. Date birthday;
  6. @Override
  7. protected Object clone() throws CloneNotSupportedException {
  8. Pig pig =(Pig)super.clone();
  9. //深克隆
  10. pig.birthday = (Date)pig.birthday.clone();
  11. return pig;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public Date getBirthday() {
  20. return birthday;
  21. }
  22. public void setBirthday(Date birthday) {
  23. this.birthday = birthday;
  24. }
  25. public Pig(String name, Date birthday) {
  26. this.name = name;
  27. this.birthday = birthday;
  28. }
  29. @Override
  30. public String toString() {
  31. return "Pig{" +
  32. "name='" + name + '\'' +
  33. ", birthday=" + birthday +
  34. '}'+super.toString();
  35. }
  36. }

3、结构性模式

适配器模式

意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
主要解决:主要解决在软件系统中,常常要将一些”现存的对象”放到新的环境中,而新环境要求的接口是现对象不能满足的。
何时使用: 1、系统需要使用现有的类,而此类的接口不符合系统的需要。 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。 3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

实现

我们有一个 MediaPlayer 接口和一个实现了 MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。
我们还有另一个接口 AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。
我们想要让 AudioPlayer 播放其他格式的音频文件。为了实现这个功能,我们需要创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。
AudioPlayer 使用适配器类 MediaAdapter 传递所需的音频类型,不需要知道能播放所需格式音频的实际类。AdapterPatternDemo 类使用 AudioPlayer 类来播放各种格式。
20201204-adapter.png
ss.png

外观模式

定义:提供一个统一接口用来访问子系统中的一群接口,外观模式定义一个高层接口,让子系统更易用

使用场景:

1.子系统复杂,增加外观模式提供简单调用接口,

2.构建多层系统结构,利用外观模式作为每层的入口,简化层间调用

IGiftExchangeSerice作为访问三个子系统的一个高层接口,提供给Test应用层

  1. package com.lilei.design.pattern.structural.facade;
  2. /**
  3. 实现类调用子系统
  4. */
  5. public class IGiftExchangeServiceImpl implements IGiftExchangeService {
  6. private QualifyService qualifyService = new QualifyService();
  7. private ShippingService shippingService = new ShippingService();
  8. private PointsPaymentService pointsPaymentService = new PointsPaymentService();
  9. @Override
  10. public void giftExchange(PointGift pointGift) {
  11. if (qualifyService.isAvailable(pointGift)) {
  12. if (pointsPaymentService.pay(pointGift)) {
  13. String number = shippingService.shipGift(pointGift);
  14. System.out.println("兑换成功,物流号为:" + number);
  15. }
  16. }
  17. }
  18. }

装饰者模式:

定义 在不改变类的基础上,将功能附加到对象上

适用场景 拓展一个类的功能或给类添加附加职责

  1. package com.lilei.design.pattern.decorator.v2;
  2. public class AbstractDecorator extends ABatterCake {
  3. //装饰者模式的核心,将要装饰的对象传递到装饰类中 复写其方法
  4. private ABatterCake aBatterCake;
  5. public AbstractDecorator(ABatterCake aBatterCake) {
  6. this.aBatterCake = aBatterCake;
  7. }
  8. @Override
  9. protected String getDesc() {
  10. return aBatterCake.getDesc();
  11. }
  12. @Override
  13. protected int getPrice() {
  14. return aBatterCake.getPrice();
  15. }
  16. }
  1. package com.lilei.design.pattern.decorator.v2;
  2. public class EggDecorator extends AbstractDecorator{
  3. public EggDecorator(ABatterCake aBatterCake) {
  4. super(aBatterCake);
  5. }
  6. @Override
  7. protected String getDesc() {
  8. return super.getDesc()+"加一个鸡蛋";
  9. }
  10. @Override
  11. protected int getPrice() {
  12. return super.getPrice()+1;
  13. }
  14. }
  1. package com.lilei.design.pattern.decorator.v2;
  2. public class SausageDecorator extends AbstractDecorator{
  3. public SausageDecorator(ABatterCake aBatterCake) {
  4. super(aBatterCake);
  5. }
  6. @Override
  7. protected String getDesc() {
  8. return super.getDesc()+"加一根火腿肠";
  9. }
  10. @Override
  11. protected int getPrice() {
  12. return super.getPrice()+2;
  13. }
  14. }
  1. package com.lilei.design.pattern.decorator.v2;
  2. public class Test {
  3. public static void main(String[] args){
  4. ABatterCake aBatterCake = new BatterCakeImpl();
  5. //每次套娃,入参是新的对象
  6. aBatterCake = new EggDecorator(aBatterCake);
  7. aBatterCake = new EggDecorator(aBatterCake);
  8. aBatterCake = new SausageDecorator(aBatterCake);
  9. System.out.println(aBatterCake.getDesc()+"price "+aBatterCake.getPrice());
  10. }
  11. }

适配器模式

定义:将一个类的接口转换成客户期望的另一个接口

享元模式

定义:提供了减少对象数量从而改善应用所需的对象结构的方式

运用共享技术有效地支持大细粒度的对象

应用于系统底层,系统有大量相识对象,需要缓冲池的场景

4、行为形模式

策略模式(&&)

定义:定义了算法家族,分别封装起来,让他们之间可以相互转换,模式让算法的变化不会影响到使用算法的用户

  1. 我的理解:将具体的,细粒度小的业务逻辑抽象为策略

适用场景:有大量的if else

  1. 一个系统要动态的在几种算法(策略)装选择一种
  1. package com.lilei.design.pattern.strategy;
  2. public interface PromotionStrategy {
  3. void doPromotion();
  4. }
  1. package com.lilei.design.pattern.strategy;
  2. public class ManjianStrategy implements PromotionStrategy {
  3. @Override
  4. public void doPromotion() {
  5. System.out.println("执行满减策略");
  6. }
  7. }
  1. package com.lilei.design.pattern.strategy;
  2. public class PromotionActivity {
  3. private PromotionStrategy promotionStrategy;
  4. public PromotionActivity(PromotionStrategy promotionStrategy) {
  5. this.promotionStrategy = promotionStrategy;
  6. }
  7. public void execPromotionStrategy(){
  8. promotionStrategy.doPromotion();
  9. }
  10. }
  1. package com.lilei.design.pattern.strategy;
  2. public class Test {
  3. public static void main(String[] args){
  4. PromotionActivity promotionActivity = new PromotionActivity(new ManjianStrategy());
  5. promotionActivity.execPromotionStrategy();
  6. }
  7. }

结合工厂模式

  1. package com.lilei.design.pattern.strategy;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. public class PromotionFactory {
  5. private static Map<String,PromotionStrategy> PROMOTION_MAP = new HashMap<>();
  6. static {
  7. PROMOTION_MAP.put(PromotionKey.FANXIAN,new FanXIanStrategy());
  8. PROMOTION_MAP.put(PromotionKey.MANJIAN,new ManjianStrategy());
  9. }
  10. private PromotionFactory(){}
  11. private static final PromotionStrategy NO_PROMOTION = new EmptyStrategy();
  12. public static PromotionStrategy getPromotionStrategy(String promotionKey){
  13. PromotionStrategy promotionStrategy = PROMOTION_MAP.get(promotionKey);
  14. return promotionStrategy==null ? NO_PROMOTION : promotionStrategy;
  15. }
  16. private interface PromotionKey{
  17. String FANXIAN = "FANXIAN";
  18. String MANJIAN = "MANJIAN";
  19. }
  20. }
  1. PromotionActivity promotionActivity = new PromotionActivity(PromotionFactory.getPromotionStrategy("FANXIAN"));
  2. promotionActivity.execPromotionStrategy();

由工厂动态的选择

观察者模式

定义:定义了对象之间一对多的依赖,让多个观察者同时监听某个主题对象,当主题对象发生改变,所有的观察者都会受到通知并更新

责任链模式(&&)

定义:为请求创建接收此次请求的链

使用 :一次请求要多个对象中的一个或几个协作完成

备忘录模式

模板方法模式(&&)

定义:定义了一个算法骨架,并允许子类为一个或多个步骤提供实现

一次性实现一个算法不可变的部分,将可变的部分提供给子类实现

  1. package com.lilei.design.pattern.behavoral.templatemthod;
  2. /**
  3. * 定义算法(业务逻辑)的骨干
  4. */
  5. public abstract class ACourse {
  6. protected final void makeCourse(){
  7. makePPT();
  8. makeVideo();
  9. if (needWriteArticle())
  10. makeArticle();
  11. packageCourse();
  12. }
  13. final void makePPT(){
  14. System.out.println("制作PPT");
  15. }
  16. final void makeVideo(){
  17. System.out.println("录制视频");
  18. }
  19. void makeArticle(){
  20. System.out.println("编写笔记");
  21. }
  22. /**
  23. 钩子方法
  24. */
  25. protected boolean needWriteArticle(){
  26. return false;
  27. }
  28. /**
  29. * 开放给子类
  30. */
  31. abstract void packageCourse();
  32. }
  1. package com.lilei.design.pattern.behavoral.templatemthod;
  2. public class DesignPatternCourse extends ACourse {
  3. @Override
  4. void packageCourse() {
  5. System.out.println("提供java源代码");
  6. }
  7. @Override
  8. protected boolean needWriteArticle() {
  9. return true;
  10. }
  11. }
  1. package com.lilei.design.pattern.behavoral.templatemthod;
  2. public class Test {
  3. public static void main(String[] args){
  4. System.out.println("制作java课程------start-----");
  5. ACourse aCourse = new DesignPatternCourse();
  6. aCourse.makeCourse();
  7. System.out.println("制作java课程------end-----");
  8. }
  9. }

迭代器模式

定义:顺序访问一个集合对象的各个方法,且不暴露该对象的内部表示,为不同的集合结构提供一个统一的接口

中介者模式

命令模式

访问者模式

解释器模式

状态模式(&&)

定义:允许一个对象在其内部状态改变时,改变它的行为

适用场景:一个对象存在多个状态(不同状态行为不同),且状态可以相互转换

例子:当一个订单在处于创建未付款的状态下可以付款,但订单处于关闭的状态下是不可付款的。

  1. package com.lilei.design.pattern.behavoral.state;
  2. /**
  3. * 上下文环境对象
  4. */
  5. public class CourseVideoContext {
  6. //状态的引用,决定了当前状态
  7. private CourseVideoState courseVideoState;
  8. //四种状态实例
  9. public final static PlayState PALY_STATE = new PlayState();
  10. public final static SpeedState SPEED_STATE = new SpeedState();
  11. public final static PauseState PAUSE_STATE = new PauseState();
  12. public final static StopState STOP_STATE = new StopState();
  13. public CourseVideoState getCourseVideoState() {
  14. return courseVideoState;
  15. }
  16. public void setCourseVideoState(CourseVideoState courseVideoState) {
  17. this.courseVideoState = courseVideoState;
  18. //维护CourseVideoState类中CourseVideoContext的引用 ,用于CourseVideoState实现类使用CourseVideoContext切换状态
  19. this.courseVideoState.setCourseVideoContext(this);
  20. }
  21. //定义了状态切换的方法
  22. public void play(){
  23. this.courseVideoState.play();
  24. }
  25. public void speed(){
  26. this.courseVideoState.speed();
  27. }
  28. public void pause(){
  29. this.courseVideoState.pause();
  30. }
  31. public void stop(){
  32. this.courseVideoState.stop();
  33. }
  34. }
  1. package com.lilei.design.pattern.behavoral.state;
  2. public abstract class CourseVideoState {
  3. //上下文环境的引用
  4. protected CourseVideoContext courseVideoContext;
  5. public void setCourseVideoContext(CourseVideoContext courseVideoContext) {
  6. this.courseVideoContext = courseVideoContext;
  7. }
  8. abstract void play();
  9. abstract void speed();
  10. abstract void pause();
  11. abstract void stop();
  12. }
  1. package com.lilei.design.pattern.behavoral.state;
  2. public class PauseState extends CourseVideoState {
  3. @Override
  4. void play() {
  5. this.courseVideoContext.setCourseVideoState(CourseVideoContext.PALY_STATE);
  6. }
  7. @Override
  8. void speed() {
  9. this.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
  10. }
  11. @Override
  12. void pause() {
  13. System.out.println("视频处于快进状态!");
  14. }
  15. @Override
  16. void stop() {
  17. this.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
  18. }
  19. }
  1. package com.lilei.design.pattern.behavoral.state;
  2. public class Test {
  3. public static void main(String[] args){
  4. CourseVideoContext courseVideoContext = new CourseVideoContext();
  5. courseVideoContext.setCourseVideoState(new PlayState());
  6. System.out.println("当前状态:"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());
  7. courseVideoContext.pause();
  8. System.out.println("当前状态:"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());
  9. courseVideoContext.speed();
  10. System.out.println("当前状态:"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());
  11. courseVideoContext.stop();
  12. System.out.println("当前状态:"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());
  13. courseVideoContext.speed();
  14. }
  15. }

当前状态:PlayState
当前状态:PauseState
当前状态:SpeedState
当前状态:StopState
ERROR,停止状态不能快进