一、前言

23种设计模式,背后其实是7大设计原则,即每个设计模式都归属于一个或多个设计原则。

二、UML类图

描述类与类之间关系

1.依赖

依赖:一个类的对象作为另一个类的局部变量
依赖uml类图: 虚线加箭头

2 继承

继承类图是实线加三角
实现接口是虚线加三角

3 关联

关联类图 实现加箭头
一个类的变量作为另一个类的字段
a.组合 关系强 比如:鸟和翅膀 ( uml关联细分 组合 实心菱形加箭头)
b.聚合 关系弱 比如:雁群和大雁 ( uml关联细分 聚合 空心菱形加箭头)

三、设计原则

1 单一职责

每个方法、类、框架都只负责一件事,功能单一
比如
Math.round(),只负责四舍五入的方法,其它不管(方法)
Read类 只负责读取文本文件(类)
SpringMVC 只负责MVC的开发(框架)

2 开闭原则

开闭原则(Open Closed Principle,OCP)对扩展新功能开放,对修改旧功能关闭

3 接口隔离原则

使用多个专门的接口比使用单一的总接口要好
举例:UserDao 专门用来做用户的CRUD
CarDao 专门用来做汽车的CRUD
BookDao 专门用来做书的CRUD
避免定义一个Dao既做用户的CRUD,也做汽车的CRUD,也做书的CRUD

4 依赖倒置原则

上层(调用别的方法)不能依赖于下层(被其它方法调用的),他们都应该依赖于抽象
举例:dao,service是通过dao接口+dao工厂来访问下层dao的实现,在以后扩展dao实现的时候,上层service是不用修改的

5 迪米特法则(最少知道原则)

一个类对于其它类要知道的越少越好(封装),只和朋友(类中的字段,方法的参数,方法的返回类型,方法内的实列化局部变量)通信

6 里氏替换原则

任何能使用父类对象的地方都应该能透明的替换为子类对象,也就是说子类对象可以随时随地替换父类对象,且替换完以后语法不会报错,业务逻辑也不会出现问题

7 组合优于继承

如果父类和子类作者不是同一个人,就慎用继承,应该使用组合,组合避免了重写,继承还继承了不想要的方法,因为父类作者不知道未来用户会重写自己的什么方法,子类作者也不知道作者在未来的版本里会改写什么方法,或添加什么新方法。Stack反面教材 addAll–add
如果父类和子类作者是同一个人,可以使用继承

方法重写的弊端:一旦重写了父类的莫一个方法,则父类的中的其它方法,

继承是一个类继承另外一个类
我们已经知道类和类之间有3种
a、继承
b、依赖 一个类的对象作为另外一个类的局部变量(方法里对象)
c、关联 一个类的对象作为另外一个类的字段,
其中关联可以细分为
组合(关系强),
聚合(关系弱 )
组合优于继承中的组合,其实指的就是关联关系

四、设计模式

1 工厂模式

简单工厂(静态工厂)

作用:把具体产品的类型,从客户端解耦
相关概念:
1.产品:new处理的对象,实例化出来的对象
2.抽象产品:抽象类、接口
3.产品簇 :多个有内在联系或有逻辑关系的产品(多个产品等级,多个产品组成一个产品簇)
4.产品等级: 不同产品簇中的相同产品

优点:1、把具体产品的类型,从客户端代码解耦出来
2、服务端如果修改了产品的类名,客户端也不知道,
这便符合了面向接口(不仅仅指接口,只要下层给上层暴露的,公共的方法,公共的类都可以叫 接口)编程的思想,也符合迪米特法则
缺点:1.客户端不得不死记硬背常量与具体产品的映射关系,比如1对应汉堡包,2对应面条
2.如果具体产品特别多,则简单工厂变得十分臃肿,比如有一百个具体产品,就需要在简单工厂的switch出写出100个case
3.变化来啦,客户端需要扩展具体产品的时候,势必需要修改简单工厂的代码,这样便违反了“开闭原则”

//抽象产品
interface Food{void eat();
}
class Hamburger implements Food{@Overridepublic void eat() {System.out.println("吃汉堡包");}
}
class Noodels implements Food{@Overridepublic void eat() {System.out.println("吃面条");}
}/*** 简单工厂*/
class FoodFactory{public static Food getFood(int n){Food food=null;switch (n){case 1:food=new Hamburger();break;case 2:food=new Noodels();break;}return food;}
}
/*** 客户只需要知道1对应汉堡包,里面类名Hamburger变为Hamburger2或无论怎么变客户也不知道,分开解耦啦* 里面的eat方法无论怎么变,客户端也不知道里面的变化*/
public class Review {public static void main(String[] args) {Food food=FoodFactory.getFood(1);food.eat();}
}

UML类图

工厂方法

针对于简单工厂代码问题,修改代码如果
优点:1.具备简单工厂的优点,服务器修改了具体产品类名以后,客户端不知道
2.当客户端需要扩展一个新的产品时,不需要修改作者原来的代码,只是扩展一个新的工厂而已
缺点:
1.如果产品等级一多,如果有多个产品等级,工厂类数量会爆炸式增长
杠点:
1.我们知道,简单工厂也好,工厂方法也好,服务器端具体产品变化类型后,客户端不知道,但是反观我们现在的代码,客户端仍然依赖于具体的工厂的类名,此时如果服务器段修改了工厂类名,客户端也需要修改工厂名,感觉折腾了一圈,又回到了原点
解释:工厂名字,是视为接口,作者有责任,义务保证工厂名字是稳定的,至少工厂名字比具体产品名字更加稳定
2.既然产品是我们自己客户端扩展出来的,那为什么不自己实列化呢?毕竟这个扩展出来的Lp这个产品我们自己就是作者,我们想怎么改类名,自己就可以把控,为什么还要为自己做产品自己做工厂呢
解释:作者在开发功能时,不仅仅只会开发一些抽象产品或具体产品以及对应的工厂,还会配套的搭配一些提前做好的框架
3.制作出LpFactory,是为了传给Bussiness.taste(),所以必须定义LpFactory,那为什么不从一开始就让
Bussiness.taste()方法接收Food参数呢,而是用FoodFactory 参数呢,
解释:杠点一,服务端类名改了,客户端也要跟着改,与具体产品名称偶尔

package com.jt.test;
//抽象产品
interface Food{void eat();
}
//具体产品
class Hamburger implements Food{@Overridepublic void eat() {System.out.println("吃汉堡包");}
}
class Noodels implements Food{@Overridepublic void eat() {System.out.println("吃面条");}
}class Bussiness{public static void taste(FoodFactory foodFactory){Food food=foodFactory.getFood();System.out.println("评委1:品尝");food.eat();Food food2=foodFactory.getFood();System.out.println("评委2:品尝");food2.eat();}
}interface FoodFactory{public Food getFood();
}class HamburgerFactory implements FoodFactory{@Overridepublic Food getFood() {return new Hamburger();}
}class NoodelsFactory implements FoodFactory{@Overridepublic Food getFood() {return new Noodels();}
}
//========================扩展凉皮,没有修改原代码
class Lp implements Food{@Overridepublic void eat() {System.out.println("吃凉皮");}
}class LpFactory implements FoodFactory{@Overridepublic Food getFood() {return new Lp();}
}public class Review {public static void main(String[] args) {FoodFactory foodFactory=new HamburgerFactory();Bussiness.taste(foodFactory);}
}

抽象工厂

优点:1.仍然有简单工厂和工厂方法的优点
2、抽象工厂把工厂类的数量减少了,无论有多少个产品等级,工厂就一套
杠点:1.为什么KFC工厂是汉堡包搭配可乐,不是汉堡包搭配面条,
解释:抽象工厂中,可以生产多个产品,这多个产品之间,必须有内在联系,同一个工厂的产品属于同一个产品簇,不能把不同产品簇中的产品混合到一个抽象工厂的实现类中
缺点:1.当产品等级发生变化(增删或删除),都会引起以前所有工厂代码的修改,这违反了开闭原则

结论:当产品等级比较固定时,可以考虑使用抽象工厂,如果产品等级经常变化,不建议使用抽象工厂

针对工厂方法问题,当有多个产品等级时(饮料、食物,甜品),工厂类就很多,修改代码如下

package com.jt.test;
//抽象产品
interface Food{void eat();
}interface Drink{void drink();
}
//具体产品
class Hamburger implements Food{@Overridepublic void eat() {System.out.println("吃汉堡包");}
}
class Noodels implements Food{@Overridepublic void eat() {System.out.println("吃面条");}
}class Coca implements Drink{@Overridepublic void drink() {System.out.println("喝可乐");}
}class Orange implements Drink{@Overridepublic void drink() {System.out.println("喝果汁");}
}interface Factory{Food getFood();Drink drink();
}class KFCFactory implements Factory{@Overridepublic Food getFood() {return new Hamburger();}@Overridepublic Drink drink() {return new Coca();}
}class MyFactory implements Factory{@Overridepublic Food getFood() {return new Noodels();}@Overridepublic Drink drink() {return new Orange();}
}class Bussiness{public static void taste(Factory factory){Food food=factory.getFood();System.out.println("评委1:品尝");food.eat();Drink drink=factory.drink();System.out.println("评委2:品尝");drink.drink();}
}public class Review {public static void main(String[] args) {Bussiness.taste(new MyFactory());}
}

2 原型模式

详情点我 java中浅克隆和深克隆基本了解

3 建造者模式

概念:将一个复杂对象的构建与它的表示分离。使同样的创建过程可以创建不同的表示

建造者模式与工厂模式区别:
工厂模式,只需要一个简单的new出产品集合
建造者模式,更注重,在new出产品之后,为产品属性赋值的过程

优点:1.创建对象的过程是稳定不变的(有ComputerBulder接口来稳定过程)
2.创建对象的过程只写一次,没有重复代码(指挥者完成)
3.当需要扩展指挥者的时候,不用修改之前的代码,这符合开闭原则,

package com.jt.test;
import lombok.Data;@Data
class Computer{private String cpu;private String memory;
}interface ComputerBulder{void setCpu();void setMemory();Computer createComputer();
}class AdvancedComputer implements ComputerBulder{private Computer computer=new Computer();@Overridepublic void setCpu() {computer.setCpu("i7");}@Overridepublic void setMemory() {computer.setMemory("32G");}@Overridepublic Computer createComputer() {return computer;}
}class MiddleComputer implements ComputerBulder{private Computer computer=new Computer();@Overridepublic void setCpu() {computer.setCpu("i5");}@Overridepublic void setMemory() {computer.setMemory("16G");}@Overridepublic Computer createComputer() {return computer;}
}class Director{public Computer buildComputer(ComputerBulder computerBulder){computerBulder.setCpu();computerBulder.setMemory();return  computerBulder.createComputer();}}//====================================
class LowComputer implements ComputerBulder{private Computer computer=new Computer();@Overridepublic void setCpu() {computer.setCpu("i3");}@Overridepublic void setMemory() {computer.setMemory("4G");}@Overridepublic Computer createComputer() {return computer;}
}public class BuilderPattern {public static void main(String[] args) {ComputerBulder advancedComputer = new AdvancedComputer();ComputerBulder middleComputer = new MiddleComputer();ComputerBulder lowComputer = new LowComputer();Director director=new Director();System.out.println(director.buildComputer(advancedComputer));System.out.println(director.buildComputer(middleComputer));System.out.println(director.buildComputer(lowComputer));}
}

4 模版方法设计模式

package com.jt.test;import java.util.ArrayList;
import java.util.List;abstract class Template {public void templateCompute() {long start = System.currentTimeMillis();code();long end = System.currentTimeMillis();System.out.println(end - start);}public abstract void code();
}class ListTest extends Template {@Overridepublic void code() {List<Integer> list = new ArrayList<>();for (int i = 0; i < 1000000; i++) {list.add(i);}}
}public class TemplatePattern {public static void main(String[] args) {Template listTest = new ListTest();listTest.templateCompute();}
}

5 代理模式

动态生成字节码图解

package com.jt.test;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;interface Compute {int add(int a, int b);int sub(int b, int c);
}class ComputeImpl implements Compute {@Overridepublic int add(int a, int b) {int c = a + b;return c;}@Overridepublic int sub(int a, int b) {int c = a - b;return c;}
}class MyHandler implements InvocationHandler {private Object tatget;public MyHandler(Object tatget) {this.tatget = tatget;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {System.out.println(method.getName()+"方法 开始,参数是"+ Arrays.toString(args));Object result=method.invoke(tatget, args);System.out.println(method.getName()+"方法 结束,结果是"+result);return 0;}
}public class ProxyPatternTest {public static void main(String[] args) {Compute c = new ComputeImpl();/*** 第一个参数 classLoader* 说明:要实例化一个对象,需要调用类的构造器的,在程序运行期间第一次调用构造器,就会引起类的加载* 加载类的时候,就是jvm拿着ClassLoader去加载类的字节码,只有字节码被加载到内存中,才能进一步实列出类的对象* 简单来说,只要设计到实例化对象,就一定要加载类的字节码,而加载字节码就必须使用类构造器* 下面我们使用动态代理的api来创建一个类的对象,这是一种不常用的实例化对象的方式,尽管不常用,但毕竟涉及到实列化对象* 那就一定需要加载类的字节码,也就是需要类加载器,所以我们手动把类加载器传入*/ClassLoader classLoader = Compute.class.getClassLoader();/*** 第二个参数Class[]* 说明:下面代码是用来实例化对象的,实例化对象就一定是实例化某一个类的对象,* 疑问:哪个类呢?类在哪里?字节码又在哪里?* 这个类其实并不在硬盘上,而是在内存中,是由动态代理在内存中”动态生成的“(见图便理解)* 要知道这个在内存中直接生成的字节码,会自动去实现下面方法中的第2个参数中所指定的接口* 所以利用动态代理生成的代理对象就能转成Compute接口类型,则这个代理对象拥有add,divide方法*//*** 第三个参数 InvocationHandler* 我们已经知道下面的代理对象proxy所属的类,实现了Compute接口,所以这个代理对象就有add,divide方法* 注意:每次对代理对象任何方法的调用,都不会进入真正的实现方法中,而是通通进入第3个参数的invoke方法中*/Compute proxy=(Compute) Proxy.newProxyInstance(classLoader,new Class[]{Compute.class},new MyHandler(c));proxy.add(1,2);proxy.add(1,2);System.out.println("over");}
}

6 适配器模式

根据已有接口,生成想要的接口

package com.jt.test.pattern;public class AdapterPattern {public static void main(String[] args) {Foo foo = new Foo();AdapterFoo adaptorFoo = new AdapterFoo(foo);System.out.println(adaptorFoo.add(1, 2));}
}class Foo {public int add(int a, int b, int c) {return a + b + c;}
}class AdapterFoo {private Foo foo;public AdapterFoo(Foo foo) {this.foo = foo;}public int add(int a, int b) {return foo.add(0, a, b);}
}

7 策略模式

package com.jt.test.pattern;import lombok.Setter;public class StrategyPattern {public static void main(String[] args) {Role role = new Role("骑士");role.setWeapon(new Sword());role.fight();role.setWeapon(new Axe());role.fight();}
}class Role {private String name;@Setterprivate Weapon weapon;public Role(String name) {this.name = name;}public void fight() {weapon.attach();}}interface Weapon {void attach();
}class Sword implements Weapon {@Overridepublic void attach() {System.out.println("用剑打");}
}class Axe implements Weapon {@Overridepublic void attach() {System.out.println("用斧头打");}
}

8 组合模式

但凡使用属性结构的地方,都使用组合模式
**适配器模式 装饰器模型 **

新手小白入门之设计模式相关推荐

  1. 3DMax”——新手小白入门篇

    3Dmax 是一个数字化三维制作软件,常简称为3Ds Max或MAX,是Discreet公司开发的(后被Autodesk公司合并)基于PC系统的三维动画渲染和制作软件.其前身是基于DOS操作系统的3D ...

  2. Java新手小白入门篇 Java基础(一)

    Java新手小白入门篇 Java基础 Java新手小白入门篇 Java基础(知识点体系汇总) Java新手小白入门篇 Java基础(一) Java新手小白入门篇 Java基础(二) Java新手小白入 ...

  3. 从新手小白入门MFC框架-黄强-专题视频课程

    从新手小白入门MFC框架-806人已学习 课程介绍         微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是微软公司提供的一个类库(class li ...

  4. 适合新手小白入门的前端书籍

    总所周知,学习前端肯定离不开书籍的辅导,很多新手小白不知道该怎么选择,以及是否选对了书籍,本文就以过来人身份,给大家推荐一下新手小白学习过程中需要或可以用到的书籍. 一,html+css阶段: 1.& ...

  5. 新手小白入门TMS320F28335

    TMS320F28335数字信号处理控制器的小白入门 笔者是一名普通大学生,自学28335曾经做过许多弯路.写到此文,希望能帮助到大家.28335芯片是由美国德州仪器公司开发的一款DSC(具备数字信号 ...

  6. 新手小白入门latex排版

    今天的新知识学习来自于老师让我修改一篇sci的格式 "按照remote sensing用latex排版发我pdf" 一句话把我整蒙了 那就开始今天的学习吧 1.软件推荐 这里不推荐 ...

  7. 新手小白入门编程第3讲 JAVA入门案例

    1 HelloWorld案例 1.1 工作空间设置 工作空间就是一个文件夹,用来保存我们所有的开发文件和代码等等. 工作空间也是可以切换的,但是切换了工作空间,我们对于eclipse的设置就重置了. ...

  8. Java新手小白入门篇 项目 - 深海杀手

    文章目录 潜艇游戏需求: 一.day01 二.day02 三.day03 四.day04 五.day05 六.day06 七.day07 八.day08 九.day09 潜艇游戏需求: 所参与的角色: ...

  9. Java新手小白入门篇 Java项目的构建

    前言 之前我们已经讲解了 JDK的下载安装及配置操作 和 IDEA的下载和安装 ,学习Java的准备工作我们已经做好了,下面我们需要做的就是创建项目,并且写我们的 Java 程序了 一.如何使用IDE ...

最新文章

  1. linux iptables 数据流程详解 4表5链的关系
  2. VBA 中判断汉字的方法
  3. Keep Walking!
  4. Java内存溢出分析
  5. spark streaming 5: InputDStream
  6. 【编程导航】这本小书,把常考算法题讲活了!
  7. 小木棍(信息学奥赛一本通-T1442)
  8. java的接口语法_JAVA接口的基本语法
  9. 【王道考研计算机网络】—计算机网络的概念 组成 功能 分类
  10. 明天发布一个基于Silverlight的类Visio小型绘图工具项目。
  11. 【OpenCV】图像变换(五)-仿射变换和透视变换
  12. 江苏专转本计算机考试模拟试卷,江苏专转本计算机模拟试题 11
  13. LINUX下载编译fontconfig
  14. css中margin标记可以带一个、二个、三个、四个参数,各有不同的含义
  15. 机房服务器巡视项目,年底,机房巡检不能少
  16. 鄂州市网站建设多少钱,鄂州市建设企业网站要多少钱
  17. 人脸识别、活体检测、人脸识别面临的挑战
  18. android+属性动画+高度,android 自定义view+属性动画实现充电进度条
  19. 基于SSH+MySQL+Bootstrap的高校实验室预约管理系统
  20. HDU——1013(字符串+数学)Digital Roots

热门文章

  1. PHP魔术方法的总结
  2. 磁盘IOPS测试指南
  3. K8s平台部署企业级项目案例
  4. 【空间分析】莫兰指数与Geary‘s Python实现
  5. 利用 MediaPipe 和 TensorFlow.js 检测 3D 手部姿态
  6. 密码学之Hash散列算法
  7. _IOR, _IOW解释
  8. 什么是Mybatis?
  9. 马尔可夫模型 | Python实现生成和拟合隐马尔可夫模型(HMM)
  10. 阿里大于短信验证码接口