0.为什么我要学习设计模式呢?
我发现mysql的jdbc有factory有工厂模式(编程思想,不指定语言都可以用)
mq有一个QueueBuilder().setArg().xxx().build建造者模式,单例模式貌似也遇到过,前端也遇到了好几个设计模式的问题,比如prototype深拷贝和浅拷贝 所以我决定系统的学习一下设计模式…
1.java面试题
原型设计模式问题
1.使用UML类图画出原型模式核心角色
2. 原型设计模式的深拷贝和浅拷贝是什么,并写深拷贝2种方式的源码 clone方法实现和序列化实现
3.spring空间哪里使用原型模式,对源码进行分析 beans.xml
4.new ClasPathXmlApplicationContext(“beans.xml”);
Object bean =application.getBean(“id01”)
getBean(String name){ return doGetBean(name,null,null,false)}
doGetBean(…){
else if(mbd.isPrototype){
//创建bean,面试官希望实际使用过设计模式看过源代码
}
}设计模式的七大原则
1.单一职责原则
2.接口隔离原则
3.依赖倒转(倒置)原则
4.里氏替换原则
5.开闭原则ocp 工厂模式有使用
6.迪米特法则
7.合成复用原则
类图来说明设计原则金融借贷平台 有审核-发布-抢单模式.随着操作不同改变得到状态.使用状态模式进行设计,并完成代码
我们通常使用if else 判断状态对应的修改状态,添加一种功能导致代码更加臃肿.没有管理好状态就会有严重bug解释器设计模式是什么? 画他的uml类图.spring框架哪里用到它,源码分析
SepelExpressionParser类单例设计模式 有几种实现方式8种
1.饿汉式 2种
2.懒汉式 3种
3.双重检查
4.静态内部类
5.枚举
2.设计模式 design pattern
- 是解决软件设计中普遍存在(反复出现)的问题的解决方案,由1990 erich Gamma等人从建筑领域引入到计算机领域的
- 高楼大厦(扩展性稳定性,复用性 维护性 可读性)和小破屋 在之前的基础上加一个功能后简单可以维护
- 使用的地方: 面向对象->功能模块(设计模式+算法)->框架[用多种设计模式]->框架[服务器集群]
- 是站在项目结构合理性的角度,而不是实现功能角度,实现功能可能压根不用设计模式(我自己就深有体会,代码虽然写的方式有千百万种,只是我们写的代码量级没有达到某个层次,没有站在可维护性,可读性的角度看)
3.设计模式的目的
1.代码重用性(相同功能代码不用重复编写)
2.可读性(规范性,方便其他程序员阅读)
3.可拓展性(增加新功能非常方便 可维护性)
4.可靠性(加新功能对原来功能没有影响)
5.高内聚 低耦合(联系少,不相互影响,不多个调用别的功能,看到一堆代码我感觉脑袋快要炸掉了,如果一大堆代码有看的套路,就不再烧脑)
4.单一职责原则(一个类只实现一个功能,不同职责可能导致错误) 一个类只有一个职责(不是里面有一个方法) 如UserDao就是这个
//singreponsibility, 交通工具的例子
//不符合单一职责的代码,run方法明显是可以拆分成天空跑,地上跑,水里跑的.
class Vihicle{ //输入为飞机就错误了
void run(String vehicle){
sout(vehicle+"在公路上跑");
}
}
//改进1 拆分为多个Vihicle 符合单一职责原则,但是改动比较大,需要修改客户端
class RoadVihicle{ //输入为大车
void run(String vehicle){
sout(vehicle+"在公路上跑");
}
}
class AirVihicle{ //输入为飞机
void run(String vehicle){
sout(vehicle+"在天上上跑");
}
}
//改进2 ,直接在增加相同功能的方法,不用多个类,方法级别也可遵守单一职责
//方法数量足够少,才可以违反单一职责
class Vihicle{ //输入为飞机
void run(String vehicle){
sout(vehicle+"在公路上跑");
}
void runAir(String vehicle){
sout(vehicle+"在天空上跑");
}
void runWater(String vehicle){
sout(vehicle+"在水上跑");
}
}
5.接口隔离原则 interface segregation principle(最小接口原则) 一个类多个类被实现,但是使用这个通过实现类间接使用这个接口的时候,有很多方法是没有使用到了,导致代码冗余
//类依赖大的接口,需要拆分为多个小的接口,类依赖与需要的接口(产生隔离不会相互影响)
//需要把他改成最小接口 不浪费
public class singleResponsiblity {
public static void main(String[] args) {
A a = new A();
a.depend1(new B());
a.depend2(new B());
a.depend3(new B());
C c = new C();
c.depend1(new D());
c.depend4(new D());
c.depend5(new D());
}
}
interface Interface1{
void fun1();
void fun2();
void fun3();
void fun4();
void fun5();
}
class A {
void depend1(Interface1 i){
i.fun1();
}
void depend2(Interface1 i){
i.fun2();
}
void depend3(Interface1 i){
i.fun3();
}
}
class B implements Interface1{
@Override
public void fun1() {
System.out.println("A实现了fun1");
}
@Override
public void fun2() {
System.out.println("A实现了fun2");
}
@Override
public void fun3() {
System.out.println("A实现了fun3");
}
@Override
public void fun4() {
System.out.println("A实现了fun4");
}
@Override
public void fun5() {
System.out.println("A实现了fun5");
}
}
class C{
void depend1(Interface1 i){
i.fun1();
}
void depend4(Interface1 i){
i.fun4();
}
void depend5(Interface1 i){
i.fun5();
}
}
class D implements Interface1{ //因为是实现所以必须要实现全部方法,用idea的语法提示也不方便 .出他有什么明确的方法
@Override
public void fun1() {
System.out.println("D实现了fun1");
}
@Override
public void fun2() {
System.out.println("D实现了fun2");
}
@Override
public void fun3() {
System.out.println("D实现了fun3");
}
@Override
public void fun4() {
System.out.println("D实现了fun4");
}
@Override
public void fun5() {
System.out.println("D实现了fun5");
}
}
//改进!!!
public class singleResponsiblity {
public static void main(String[] args) {
A a = new A();
a.depend1(new B());
a.depend2(new B());
a.depend3(new B());
C c = new C();
c.depend1(new D());
c.depend4(new D());
c.depend5(new D());
}
}
interface Interface1{
void fun1();
}
interface Interface2{
void fun2();
void fun3();
}
interface Interface3{
void fun4();
void fun5();
}
class B implements Interface1,Interface2{ //代码可读性更好了
@Override
public void fun1() {
System.out.println("B实现了fun1");
}
@Override
public void fun2() {
System.out.println("B实现了fun2");
}
@Override
public void fun3() {
System.out.println("B实现了fun3");
}
}
class D implements Interface1,Interface3{
@Override
public void fun1() {
System.out.println("D实现了fun1");
}
@Override
public void fun4() {
System.out.println("D实现了fun4");
}
@Override
public void fun5() {
System.out.println("D实现了fun5");
}
}
class A {
void depend1(Interface1 i){
i.fun1();
}
void depend2(Interface2 i){
i.fun2();
}
void depend3(Interface2 i){
i.fun3();
}
}
class C{
void depend1(Interface1 i){
i.fun1();
}
void depend4(Interface3 i){
i.fun4();
}
void depend5(Interface3 i){
i.fun5();
}
}
6.依赖倒转原则 dependence inversion principle
1.高层模块不依赖低层模块
2.抽象不依赖于细节,细节依赖抽象
3.中心思想是 面向接口编程(在设计上非常有用)
4.抽象的相对稳定,倒转指的是 我不直接写普通类了,而是先写接口后写类
代码: //接收消息的代码 ,
//改进,调用的代码不用改变只需要增加一个接口,然后类实现他
//依赖传递!!!的三种方式(类必须有接口,类型是接口赋值,我们程序就有个缓存层)
1.通过接口传递实现依赖 //把依赖的作为参数传给实现的方法,可以在依赖的方法上加功能
public class Inversion2 {
public static void main(String[] args) {
//这里不用改代码
Person2 person = new Person2();
person.send(new Email2());
// person.open(new WeiXin2());
}
}
interface ReveiveMessage2{
void receive();
}
//接收到消息后转发给其他人
interface ReveiveAndSend{ //为了把依赖(也是接口的思想)
void send(ReveiveMessage2 depend);
}
class Email2 implements ReveiveMessage2{ //多个实现
//public default private protected
@Override
public void receive() {
System.out.println("接收邮箱消息");
}
}
//class WeiXin2 implements ReveiveMessage2{//多个实现
// @Override
// public void receive() {
// System.out.println("接收微信信息");
// }
//}
class Person2 implements ReveiveAndSend{
@Override
public void send(ReveiveMessage2 depend) { //使用
depend.receive();
System.out.println("接收的信息转发出去");
}
}
- (开发使用)1的改进 ,//使用依赖的类(实现接口,构造方法调用依赖初始化,实现的方法不用参数专门来实现功能)和依赖
public class Inversion3 {
public static void main(String[] args) {
Person3 person = new Person3(new Email3());
person.send();
// person.open(new WeiXin2());
}
}
interface ReveiveMessage3{
void receive();
}
//接收到消息后转发给其他人
interface ReveiveAndSend3{ //为了把依赖(也是接口的思想)
void send();
}
class Email3 implements ReveiveMessage3{ //多个实现
//public default private protected
@Override
public void receive() {
System.out.println("接收邮箱消息");
}
}
//class WeiXin2 implements ReveiveMessage2{//多个实现
// @Override
// public void receive() {
// System.out.println("接收微信信息");
// }
//}
class Person3 implements ReveiveAndSend3{
ReveiveMessage3 re;
Person3(ReveiveMessage3 re){
this.re=re;
}
@Override
public void send() { //使用
re.receive();
System.out.println("接收的信息转发出去");
}
}
3. (开发使用)和2差不多,通过set方法给接口赋值(可能没有使用set导致空指针)
public class Inversion4 {
public static void main(String[] args) {
Person4 person = new Person4();
person.setRe(new Email4());
person.send();
// person.open(new WeiXin2());
}
}
interface ReveiveMessage4{
void receive();
}
//接收到消息后转发给其他人
interface ReveiveAndSend4{ //为了把依赖(也是接口的思想)
void send();
}
class Email4 implements ReveiveMessage4{ //多个实现
//public default private protected
@Override
public void receive() {
System.out.println("接收邮箱消息");
}
}
//class WeiXin2 implements ReveiveMessage2{//多个实现
// @Override
// public void receive() {
// System.out.println("接收微信信息");
// }
//}
class Person4 implements ReveiveAndSend4{
ReveiveMessage4 re;
@Override
public void send() { //使用
re.receive();
System.out.println("接收的信息转发出去");
}
public void setRe(ReveiveMessage4 re) {
this.re = re;
}
}
7.里氏替换原则(解决子类重写父类方法,导致子类方法调用错误(无意识的,我以为调用了继承的父类的方法),造成的巨大影响,破坏继承体系)
- 介绍 :是Liskov 麻省理工大学的女士1988年提出的
- 子类不要重写父类的方法(所有用基类的地方必须透明的使用其子类对象[子类重写所有父类的方法,相当于父类没有使用])
耦合性(关联,修改了另外一个影响另外一个)- 适当情况下,共同继承一个基类,然后使用
1继承类图 generalization
聚合 如4聚合UML类图
组合(把A类成为B的私有成员,然后创建B的方法调用A) composite 如2组合UML类图
-------改进前-----
public class LiskReplace {
public static void main(String[] args) {
B b = new B();
System.out.println(b.add(1, 2));
}
}
class A{ //如果我们还看到父类这个方法,就会和子类混淆实现的具体步骤
//两数相加
public int add(int a,int b){
return a+b;
}
}
class B extends A{
//两数相加,我无意识的增加了这个方法导致父类方法被覆盖
public int add(int a,int b){
return a+b-1;
}
public int sub(int a,int b){
return a-b;
}
}
-----改进后-----
public class LiskReplace {
public static void main(String[] args) {
A a = new A();
System.out.println(a.add(1, 2));
}
}
class Base{ //建立一个基类共同继承,其实这里是为了设计,说明A和B和同一类功能的类型,可读性提高
}
class A extends Base{ //因为AB是单独的所以不会混淆方法覆盖
//两数相加
public int add(int a,int b){
return a+b;
}
}
class B extends Base{ // 去掉继承 extends A,变成聚合 组合 依赖的方式,
public int add(int a,int b){
return a+b-1;
}
public int sub(int a,int b){
return a-b;
}
}
8.开闭原则 Open Closed Principle(ocp) (前面的原则都是为了这个原则,是基础和最重要的原则)
- 类,模块,函数 扩展开放(开发者) 修改关闭(使用这个类函数的使用者) 抽象构建框架,实现拓展细节
- 通过扩展实现变化(增加代码),不是通过修改代码实现变化(已有的代码修改,可能会出bug) //依赖倒置的那个案例也是满足ocp原则
- 改进方法,增加一个抽象类或接口,使用方调用这个抽象类
----改进前的代码—
public class Ocp {
public static void main(String[] args) {
ShapeEditor shapeEditor = new ShapeEditor(new Circle());
ShapeEditor tri = new ShapeEditor(new Triangle());
new ShapeEditor(new RectAngle()); //(3)使用者修改代码,本来就要修改
}
}
class ShapeEditor{
ShapeEditor(Shape shape){
if (shape.type==1){
Circle circle = new Circle();
circle.draw();
}else if(shape.type==2){
Triangle triangle = new Triangle();
triangle.draw();
}else if(shape.type==3){ //(2)增加一个判断,修改类,增加了不需要的判断, 这里不应该去修改 ,要满足扩展开放,修改关闭
RectAngle rectAngle = new RectAngle();
rectAngle.draw();
}
}
}
class Shape{
int type;
Shape(){
}
Shape(int type){
this.type=type;
}
}
class Circle extends Shape{
Circle(){
super.type=1;
}
void draw(){
System.out.println("绘制圆形");
}
}
class Triangle extends Shape{
Triangle(){
super.type=2;
}
void draw(){
System.out.println("绘制三角形");
}
}
//如果我增加一个长方形,需要增加的代码如(1)(2)(3)
class RectAngle extends Shape{ //(1) 最基础的是增加这个类和修改type为3
RectAngle(){
super.type=3;
}
void draw(){
System.out.println("绘制长角形");
}
}
----改进后的代码,暴力节省判断的代码,只需要改变超类为抽象类()—
public class Ocp {
public static void main(String[] args) {
ShapeEditor shapeEditor = new ShapeEditor(new Circle());
ShapeEditor tri = new ShapeEditor(new Triangle());
new ShapeEditor(new RectAngle()); //(3)使用者修改代码,本来就要修改
}
}
class ShapeEditor{
ShapeEditor(Shape shape){
shape.draw(); //(1)为什么会导致这样的结果呢?,因为抽象类和接口一样会调用他实现的对应的类
}
}
abstract class Shape{
int type;
abstract void draw(); //(2)
}
class Circle extends Shape{
Circle(){
super.type=1;
}
void draw(){
System.out.println("绘制圆形");
}
}
class Triangle extends Shape {
Triangle(){
super.type=2;
}
void draw(){
System.out.println("绘制三角形");
}
}
class RectAngle extends Shape{
RectAngle(){
super.type=3;
}
void draw(){
System.out.println("绘制长角形");
}
}
//使用场景,他是为了使用者调用的时候,不改变原来的代码,只做增加类,不在类方法里面修改
//多用抽象和继承配合一起使用
9.迪米特法则demeter (最少知道原则),一个类对外只提供public方法不泄漏任何信息,
1.类方法内(局部变量)是非直接朋友,外面或者是返回值和方法传入的参数就是直接朋友
2.可以降低类和类的耦合度,类不可能完全没有耦合
3.改进的方案 把其他类有违反迪米特法则的代码,写到我们要使用的类的方法
public class demeter {
public static void main(String[] args) {
Manager manager = new Manager();
}
}
class Manager{
Manager(){
Employee employee=new Employee(); //违反迪米特法则
employee.work();
}
}
class Employee{
void work(){
System.out.println("开始工作");
}
}
//使用迪米特法则改进
public class demeter {
public static void main(String[] args) {
Manager manager = new Manager();
manager.start(new Employee());
}
}
class Manager{
Employee employee=new Employee();//没有违反,依赖的组合关系
Manager(){
employee.work();
// Employee employee=new Employee(); //违反
// employee.work();
}
void start(Employee employee){//没有违反
employee.work();
// Employee employee=new Employee(); //违反
// employee.work();
}
}
class Employee{
void work(){
System.out.println("开始工作");
}
}
10.合成复用原则 尽量使用合成/聚合(通过B的set方法设置A依赖)的方式,而不使用继承
如图5合成复用法则解决方案
11.设计原则核心思想
找出可能变化的地方,不要和不需要变化的地方混合在一起
针对接口编程,而不是针对实现(不是 implements关键字,是方法实现的具体过程)编程
松耦合
Dependency 依赖 (另外一个类 调用方法传入参数)
Association 关联(会使用到)
Generalization泛化(继承)
Realization(实现)
Aggregation聚合(使用set方法设置另外一个类)<(耦合度) Composite组合直接在构造方法初始化另外一个类Note 对UML注释
//工具Eclipse UML插件 AmasterUML.jar导入
//idea自带 file->setting–>tools—>diagrams—>java class diagrams—>钩上fields constructor和methods—>apply—>要画的文件夹右键
diagrams---->show diagram—> java class diagrams 自动生成完工…
12.UML类图(最重要的是类图,用例图次要)用于程序员之间交流
如图 6.类图的分类
- 在eclipse .java拖拽直接变成类图,在同一文件夹下写类图逻辑会比较清晰
- 依赖关系(如果没有这个类会编译不通过) (总之就是用到,不管是直接或者间接)(形容比较广泛的关系)
1.类中使用到对方
2.类的成员属性
3.方法的返回值
4.方法接收的参数类型
5.方法内使用到
//最下面一条线是依赖关系- 泛化关系 依赖的特例 就是继承关系
- 实现关系 依赖的特例 类—>实现–>接口
关联关系 依赖的特例 一对一,一对多关系
如 一个Person对应一个IDCard类 Person-1—1>IDCard 1----n>List集合 Map
public class Person{ private IDCard card;}聚合关系aggregation(重要) 关联关系的特例 整体和部分可以分开 鼠标和键盘可以从电脑分离
图 7.聚合关系一群人聚在一起->乌合之众
- 组合关系composition 整体和部分不可分割(只要Computer创建 mouse和monitor在成员new出来了)
图 8组合关系
你的器官是组合,(各有优点)
- 组合和聚合一起使用 .级联删除IDCard也是组合关系
图9聚合关系
13.UML统一建模语言 idea安装PlantUML插件
@startuml
title 类图
scale 1.5
/'组合关系(composition)'/
class Human {
- Head mHead;
- Heart mHeart;
..
- CreditCard mCard;
--
+ void travel(Vehicle vehicle);
}
Human *-up- Head : 组合 >
Human *-up- Heart : 组合 >
/'聚合关系(aggregation)'/
Human o-left- CreditCard : owns >
/'依赖关系(dependency)'/
Human .down.> Vehicle : dependent
/'关联关系(association'/
Human -down-> Company : associate
/'继承关系(extention)'/
interface IProgram {
+ void program();
}
class Programmer {
+ void program();
}
Programmer -left-|> Human : extend
Programmer .up.|> IProgram : implement
@enduml