【设计模式整合】20秒速记23种设计模式。设计模式7原则,UML类图。创建,结构,行为型。

设计模式7原则,UML类图。创建,结构,行为型。速记23种设计模式。

依 里 接 单 开 合 笛

建 工 抽 原 单
适 桥 组 装 享 外 代
责 命 中 解 迭 备
观 状 策 模 访
在这里插入图片描述

7原则概述

  1. 单一职责原则
  2. 接口隔离原则
  3. 依赖倒转原则
  4. 里氏替换原则
  5. 开闭原则 ocp
  6. 迪米特法则
  7. 合成复用原则
    依 里 接 单 开 合 笛

依赖倒转

  • 接口的依赖

  • 同开闭,加功能使用方不变

  • 我们发送一个消息,直接调用发送消息的 接口。

    • 具体使用的时候,用 Email 发送,那真实参数 就传递Email类

里式替换

  • 继承必须确保 超类所拥有的性质

    • 在子类中 依然成立
  • 增加功能时:把以前的类依赖过来,原逻辑用原来的方法(包一层)。

    • 提取父类,使用组合关系。

接口隔离

  • 要什么功能实现什么接口

  • 接口 已经最小化,不会有 冗余的实现

单一职责

  • 汽车在地上跑
    • 汽车类,地上跑的方法。
  • 极简情况,是一个的类,上面有:地上跑,天上飞的方法。

开闭原则

  • 使用方,无需改变。同依赖倒转
    • 使用的时候 依赖的是接口。
  • 新增图形 继承父类
    • 不改变其他类,父类有的方法依然存在。
    • 比如:我需要 圆周率非常精确,我就重写父类的方法。

合成复用

尽量使用合成/聚合的方式,而不是使用继承

迪米特法则

  • 最少知道原则

直接朋友,我们称出现

  • 成员变量,

  • 方法参数,

  • 方法返回值中的类为直接的朋友,

  • 而出现在局部变量中的类不是直接的朋友。

  • 陌生的类最好不要以局部变量的形式出现在类的内部。

  • 学校 打印 学院的信息,调用 学院的打印

    • 而不是:获取到学院的列表(局部变量)。违法了 迪米特

核心思想

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

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

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

UML

UML——Unified modeling language UML (统一建模语言),

是一种用于软件系统 分析和设计的语言工具

依赖关系

依赖 ----> dependency

  • 泛化(继承)—▷ generalization
  • 实现----▷ implementation 和 realization
  • 关联 — association
    • 聚合—◇ aggregation
    • 组合—♦ composite

依赖方式

  • 全局变量,所有的方法都能用
  • 局部变量
  • 形参
  • 返回值

组合 和 聚合

  • 那么 Head 和 Person 就是 组合。
    • 删除所有的人,班级也删除。就是:组合关系。
  • IDCard 和 Person 就是聚合。
    • 计算机:有 鼠标 和 显示器

关联

  • 如“1”(表示有且仅有一个),
  • “0…”(表示0个或者多个),
  • “0, 1”(表示0个或者一个),
  • “n…m”(表示n到 m个都可以),
  • “m…*”(表示至少m个)。

关联具有导航性:即双向关系或单向关系

创建型

建 工 抽 原 单

1. 建造者

  • 产品:最终产出什么样房子
  • 抽象建造者:定义每个(单个)流程
    • 具体建造者:实现 单个流程
  • 指挥者:建造房子的流程,先调用 这个方法,在调用那个。
    • 给个高楼对象 ,盖的就是高楼

StringBuilder

  • Appendable 为抽象建造者, 定义了抽象方法
    • AbstractStringBuilder 已经是建造者,只是不能实例化。建造方 法的实现。
      • StringBuilder 即充当了指挥者角色,同时充当了具体的建造者

2. 工厂模式

  • 简单工厂。也叫 静态工厂模式

    • 传递 不同的类型,创建不同的类
    • JDK-Calendar
    Calendar cal = Calendar.getInstance();
    cal.get(Calendar.YEAR);
    //根据不同的类型,创建不同的Calendar类
    
  • 工厂方法

    • 抽象类,调用 抽象方法创建对象。
    • 具体的工厂,如北京工厂
      • 北京奶酪披萨
      • 北京胡椒披萨

Calendar

3. 抽象工厂

  • 工厂接口
    • 北京工厂
    • 天津工厂
  • 业务类,依赖工厂。
    • 工厂方法是:抽象类里 包含了业务 + 创建工厂的接口

4. 原型

  • implements Cloneable
  • 重写 clone() 方法
  • 默认为 浅拷贝
  • 深拷贝:对象里 包含对象,也要拷贝出不同的对象
    • A 里有B,拷贝出来C,C里 默认的还是B。浅拷贝。

实现深拷贝:

  • clone方法

    • 被引用的类,也实现 Cloneable

    • 属性重新赋值

      deep.innerTarget  = (InnerTarget)innerTarget.clone();
      
  • 对象序列化

    ObjectOutputStream(ByteArrayOutputStream).writeObject(this);
    ObjectInputStream(ByteArrayInputStream(上个ByteOutput)).readObject(); 
    //然后强转对象
    
    //输出流:有 写入的方法。
    //输入流:有 读取的方法。
    //OutputStream 和 InputStream
    //Object 包裹:ByteArray
    

beans.xml

  • spring中的 beans.xml

    • 两种方式
    <!-- 这里我们的 scope="prototype" 即 原型模式来创建 -->
     <bean id="id01" class="com.xxx.xx.Monster" 
     	scope="prototype"/>
    </beans>
         
    @Component
    @Scope("prototype")
    public class Student{
    }
    
    ClassPathXmlApplicationContext("beans.xml").getBean("id01");
    
  • scope 作用域

    prototype 代表线程每次调用这个bean都新创建一个实例。
    singleton 默认

    request 表示每个request作用域内的请求只创建一个实例。
    session 表示每个session作用域内的请求只创建一个实例。

    GlobalSession
    这个只在porlet的web应用程序中才有意义,它映射到porlet的global范围的session,

    如果普通的web应用使用了这个scope,容器会把它作为普通的session作用域的scope创建。

判断出如果是 原型,就是用 原型模式创建bean

createBean(beanName, mbd, args);

5. 单例

单例的各种实现

  1. 饿汉式(静态常量) 推荐
    1. 私有构造
    2. 创建对象实例
    3. 提供公有的访问
  2. 饿汉式(静态代码块)
  3. 懒汉式(线程不安全)
  4. 懒汉式(线程安全,同步方法)synchronized
  5. (无用)懒汉式(线程也不安全,同步代码块)
  6. 双重检查 推荐
  7. 静态内部类,创建外部对象 推荐
  8. 枚举
  9. CAS AtomicReference 的 compareAndSet
  10. ConcurrentHashMap 自己设计
静态常量 饿汉式
//饿汉式(静态变量) Singleton
class S {
	
	//1. 构造器私有化, 外部能new
	private S() {
	}
	
	//2.本类内部创建对象实例
	private final static S instance = new S();
	
	//3. 提供一个公有的静态方法,返回实例对象
	public static S getInstance() {
		return instance;
	}
}
双重检查
class Singleton {
    //可见性
	private static volatile Singleton instance;
	
	private Singleton() {}
	
	//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
	//同时保证了效率, 推荐使用
	
	public static Singleton getInstance() {
        //为null,才加锁
		if(instance == null) {
            //上锁
			synchronized (Singleton.class) {
                //再次判断 为null,才返回对象
				if(instance == null) {
					instance = new Singleton();
				}
			}
			
		}
		return instance;
	}
}
静态内部类
// 静态内部类完成, 推荐使用
class Singleton {

	//构造器私有化
	private Singleton() {}
	
	//写一个静态内部类,该类中有一个静态属性 外部类
	private static class SingletonInstance {
		private static final Singleton I = new Singleton(); 
	}
	
	//提供一个静态的公有方法,直接返回 外部类.内部类
	public static Singleton getInstance() {
		return SingletonInstance.I;
	}
}
AtomicReference
public class Singleton {
	//定义 atomic
    private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();

    //private static Singleton instance;//这个变量没用,最好注释

    private Singleton() {
    }

    //final 可以省略
    public static final Singleton getInstance() {
        //死循环
        for (; ; ) {
            //获得 这个对象。用静态的也行吧
            Singleton instance = INSTANCE.get();
            //如果不为null,就返回
            if (null != instance) return instance;
            
            //为null,就创建
            //无锁 算法,CPU指令集操作,只有一步 原子操作
            INSTANCE.compareAndSet(null, new Singleton());
            //然后 返回
            return INSTANCE.get();
        }
    }

}

Runtime

  • java.lang.Runtime 就是 经典的单例模式(饿汉式)
Runtime runtime = Runtime.getRuntime();   
runtime.totalMemory()
runtime.gc();

Process process = runtime.exec("notepad");
process.destroy();

结构型

适 桥 组 装 享 外 代

1. 适配器

  • 类 对象 接口 适配器
    • 继承被适配的接口,实现 将要输出的接口。
  • 对象
    • 实现 将要输出的接口。 聚合 被适配的类(定义被适配的类,构造传递)
  • 接口
    • 抽象类 实现接口,提供空实现。
    • 使用 抽象类,重写 自己需要的接口。

HandlerAdapter

  • Mvc的 DispatcherServlet 的 doDispatch。使用了:适配器 和 责任链
    • 通过 HandlerMapping的处理,找到 用户希望请求的 Handler。
public interface HandlerAdapter {
    //handler instanceof HttpController
	public boolean supports(Object handler);
    //(HttpController) handler).doHttpHandler()
	public void handle(Object handler);
}
//有个 ArrayList<HandlerAdapter>(); 放入这些 Handler
//使用时 遍历这个 list,取出 然后执行

2. 桥接

  • 抽象中间层,具体的折叠手机,直板手机,继承此。
  • 将实现与抽象放在两个不同的类层次中。
public abstract class Phone {
	//组合品牌
	private Brand brand;

	//全参构造器
    
	protected void open() {
		this.brand.open();
	}
}

JDBC

  • Driver就是一个顶层接口,

  • MySQL的Driver, Oracle的Driver

    DriverManager.registerDriver(new Driver());
    
  • 没有抽象类,直接用 DriverManager 桥接

    • getConnection ,根据注册的驱动 不一样,返回 不同的驱动
    • 依赖了 java.sql.Connection。 (使用:返回值 依赖)
    • client 使用 DriverManager

3. 组合

  • 又叫部分整体模式

  • 创建了对象组的树形结构

  • 表示“整体-部分”的层次关系。

  • 顶层抽象类,如orga

    • 有 抽象方法 打印
    • 有 增删改查的方法,默认实现
  • 大学 非叶子节点,重写增删改查,有 ArrayList

    • 学院 非叶子节点
      • 系 叶子节点。不重写 增删改查。没有 子List
  • 因为 非叶子节点,都有 List,可以随便添加(放入list对象,都是实现 了 orga的类)

HashMap

Map<Integer,String> hashMap=new HashMap<Integer,String>();
hashMap.put(0, "东游记");

Map<Integer,String> map=new HashMap<Integer,String>();
map.put(1, "西游记");

hashMap.putAll(map);
1. public interface Map<K,V> 提供增删改查方法
2. public abstract class AbstractMap<K,V> implements Map<K,V> 提供默认实现
3. public class HashMap<K,V> extends AbstractMap<K,V>
提供具体的实现。中间节点。
4, HashMap内部类:static class Node<K,V> implements Map.Entry<K,V> 就是叶子节点。

4. 装饰者

  • 主餐在里面,巧克力 + 牛奶 + 黑咖啡
new Chocolate(new Milk(new LongBlack()));
  • Drink
    • Coffee
      • Espresso 意大利咖啡
    • Decorator 装饰者,依赖咖啡:Drink obj;
      • Chocolate 巧克力

FilterInputStream

InputStream 就是 drink

  • File Input Stream 就是各种 咖啡

  • String Buffer xx xx

  • Byte Array xx xx

  • Filter xx xx = 这个类似 装饰器

    • Buffer xx xx = 类似 具体的调味品(巧克力),装饰的类
    • Data xx xx
    • Line Number xx xx
public class FilterInputStream extends InputStream { //是一个装饰者类Decorator
	protected volatile InputStream in //被装饰的对象 
}
DataInputStream dis = new DataInputStream(new FileInputStream("d:\\abc.txt"));       System.out.println(dis.read()); //int 读取, A 65 ,a 97        
dis.close();

5. 享元

享元模式(Flyweight Pattern) 也叫 蝇量模式: 运
用共享技术有效地支持大量细粒度的对象

  • 共享

  • 元:就是对象

  • String

  • 数据库,连接池 技术

  • 缓冲池

  • Integer都用到了 享元

String s = "hello";
String s2 = new String("hello");  
  • 棋子的位置:外部状态。随时改变。

  • 棋子的颜色:内部状态。几乎不会变。共享。

  • 抽象类 网站,抽象方法,方法里对象 是 外部状态。

    • 如:网站,被某个用户使用。使用是 外部状态
    • 真实的网站,继承 抽象网站,实现方法。
      • 定义共享的内部状态。如:构造传入。
  • 享元工厂类,有集合 充当池的作用。

    • 如果 构造传递的 内部状态,不存在,则创建。
    • 否则:直接 返回。也是 单例模式了。

Integer

        Integer x = Integer.valueOf(127);
        Integer y = new Integer(127); //废弃

        Integer z = Integer.valueOf(127);
        Integer w = new Integer(127); //废弃

        System.out.println(x.equals(y)); // 值比较为true
        System.out.println(x == y ); // 对象比较为 false

        System.out.println(x == z ); // 同样:Integer.valueOf 为true
        System.out.println(w == x ); // 和 new相比,为false
        System.out.println(w == y ); // new 的== 相比为 false
range -128 to 127,从缓存中拿,执行速度更快。否则:就创建新对象。
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

6. 外观

  • 也叫 过程模式

就是抽一层接口。

  • 对外提供更好的方法,内部复杂是自己的。

  • 简称:谁都会的设计模式。

  • 可以结合 单例模式,比如:爆米花 是单例类

  • 外观类(家庭影院):有4个方法,准备,开始,暂停,结束。

MyBatis 的 Configuration

  • MyBatis 中的Configuration 去创建MetaObject 对象使用到外观模式
public MetaObject newMetaObject(Object object) {
    
	return MetaObject.forObject
		(object, objectFactory, objectWrapperFactory, reflectorFactory);
	}
}
//MetaObject.forObject 方法很复杂,会判断不同的类型,使用不同的工厂。如:ObjectWrapper Wrapper Map Collection

7. 代理

防火墙 缓存 远程 同步 代理

静态代理,需要实现接口

implements ITeacherDao //实现相同的接口
ITeacherDao target; //定义目标对象

动态代理

  • JDK,需 实现接口
  • Cglib,内存动态的创建对象,无需要实现接口

JDK

public class ProxyFactory {

	//维护一个目标对象 , Object
	private Object target;

	//构造器 , 对target 进行初始化
	
	//给目标对象 生成一个代理对象
	public Object getProxyInstance() {
		
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), 
				new InvocationHandler() {
					
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("JDK代理开始~~");
						//反射机制调用目标对象的方法
						Object returnVal = method.invoke(target, args);
						System.out.println("JDK代理提交");
						return returnVal;
					}
				}); 
	}
	
}
Proxy.newProxyInstance
target.getClass().getClassLoader();
target.getClass().getInterfaces();
//InvocationHandler

//第三个参数
(proxy, method, args) -> {
                    System.out.println("jdk代理前");
                    Object invoke = method.invoke(t, args);
                    System.out.println("jdk代理后");
                    return invoke;
                }

Cglib

public class ProxyFactory implements MethodInterceptor {

	//维护一个目标对象
	private Object target;
	
	//构造器,传入一个被代理的对象
	
	//返回一个代理对象:  是 target 对象的代理对象
	public Object getProxyInstance() {
		//1. 创建一个工具类
		Enhancer e = new Enhancer();
		//2. 设置父类
		e.setSuperclass(target.getClass());
		//3. 设置回调函数
		e.setCallback(this);
		//4. 创建子类对象,即代理对象
		return e.create();
	}
	
	//重写  intercept 方法,会调用目标对象的方法
	@Override
	public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {

		System.out.println("Cglib代理模式 ~~ 开始");
		Object r = method.invoke(target, args);
		System.out.println("Cglib代理模式 ~~ 提交");
		return r;
	}

}
implements MethodInterceptor

		//1. 创建一个工具类
		Enhancer e = new Enhancer();
		//2. 设置父类
		e.setSuperclass(target.getClass());
		//3. 设置回调函数
		e.setCallback(this);

		//4. 创建子类对象,即代理对象
		return e.create();
		
		Object r = method.invoke(target, args);

行为型

责 命 中 解 迭 备

观 状 策 模 访

1. 责任链

  • 也叫:职责链模式(Chain of Responsibility Pattern)

  • 路障。过滤器,拦截器,你拦截通过后,我来拦截。

    • 一个对象不能处理该请求,
    • 那么它会把相同的请求传给下一个接收者
  • 小于等于5000, 由教学主任审批 (0<=x<=5000)

public abstract class Approver {

	Approver approver;  //下一个处理者
	//提供一个抽象方法	
}
		//系主任,的下一个为 学院主任
		department.setApprover(college);

HandlerExecutionChain

  • 他本身不处理请求,只是将请求分配给链上注册处理器执行,减少职责链本身与处理逻辑之间的耦合。

  • 维护了 HandlerInterceptor 的集合, 可以向其中注册相应的拦截器。

  • MVC 中央处理:Dispatcher Servlet,用了:适配器 和 责任链。doDispatch 是核心。

  • 通过URL请求找到对应的HandlerMapping,然后构建HandlerExecuteChain对象,再交给handleradapter执行。

    • Handler Interceptor 拦截 ,调用 pre Handler方法 前置方法
    • 以及 post handle 方法 后置方法
    • 响应之前,还会调用 after Completion方法
    • 异常用 @ControllerAdvice吧
HandlerInterceptor
  • 实现此接口
public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        return true;
    }

    postHandle

    //afterCompletion
    //无论是否产生异常,都会在渲染视图之后执行。
}
    <mvc:interceptors>
        <mvc:interceptor>
            <!--配置拦截器拦截的路径-->
            <mvc:mapping path="/*.do"/>
            <!--配置拦截器-->
            <bean class="xx.RoleInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
ControllerAdvice
@ControllerAdvice
public class GlobalExceptionCapture {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionCapture.class);

    public GlobalExceptionCapture() {
    }

    @ExceptionHandler({Exception.class})
    @ResponseBody
    public ResultDTO exceptionHandler(Exception e) {
        log.error("出现新异常了:${}$", ExceptionUtils.getStackTrace(e));
        ResultDTO resultDTO = ResultUtils.other(ResponseCodeEnum.SERVER_ERROR);
        return resultDTO;
    }
}

2. 命令

  • 一个控制器,控制所有家电。

  • 每个智能家电厂家都要提供一个统一的接口给app调用

  • 将“动作的请求者”从“动作的执行者”对象中解耦出来

    • 向某些对象发送请求,但是并不知道请求的接收者是谁

    • 在程序运行时指定具体的请求接收者即可

  • 将军(命令发布者)、

  • 士兵(命令的具体执行者)、

  • 命令(连接将军和士兵)。

  • 命令接口有:执行 和 退回的方法。

    • 具体的命令类,聚合:电灯。
      • 开命令:如:执行为 开。回退为:关。
      • 所以:还要写 关命令。
      • 空命令,初始化时用。省掉对空的判断。
  • 被调用者,就是 士兵。如:具体开关的电灯。

  • 遥控器,包含:开命令数组 和 关命令数组。和 撤销命令(不是数组)。

    • 初始化为 空命令。
    • 设置命令,传递 序号,开命令 和 关命令。序号为 数组下标。
    • 开命令,参数为 序号(同样也有关)。 撤销命令 记住此命令。
    • 调用撤销命令,就是:撤销命令对象.undo()

JdbcTemplate

  • StatementCallback 接口 ,类似命令接口(Command)

    • class QueryStatementCallback implements StatementCallback, SqlProvider , 匿名内
      部类, 实现了命令接口, 同时也充当命令接收者
  • 命令调用者 是 JdbcTemplate , 其中execute(StatementCallback action) 方法中,

    • 调用action.doInStatement 方法. 不同的 实现 StatementCallback 接口的对象,对应不同
      的doInStatemnt 实现逻辑
  • 不同之处在于,正规的 命令模式:命令接收者(士兵),不会实现命令的。

  • 此处的命令调用者(指挥者,将军):还充当了 整合接收者。

  • 将军(调用者):JdbcTemplate 的 query方法

    • 具体怎么调用:JdbcTemplate 的 execute方法
  • 命令接口为:StatementCallback

    • 士兵:query方法 里的 内部类:QueryStatementCallback。即:真实的命令执行者

3. 中介者

主人要看电视时,比如流程为: 闹铃响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放

客户联系中介

  • 中介给 房主 和 房主的妻子,房主的父亲 联系。

  • 房主 和 房主的妻子,代码里 不让其联系 (否则会 很复杂)

  • C(Controller控制器)是M(Model模型)和V(View视图)的中
    介者,在前后端交互时起到了中间人的作用

  • Service 也是中介者,注入各种mapper,mapper之间是 不交互的。

抽象同事类

  • 抽象同事类:依赖中介接口。提供抽象接口。

    • 具体类:闹钟 TV

      • 下面是通用的方法和代码
      		//构造遵循父类,中介者 传给父类
      		super(mediator, name);
              
      		//在创建Alarm 同事对象时,将自己放入到ConcreteMediator 对象中[集合]
      		mediator.Register(name, this);
      
      //抽象接口的实现
      		//调用的中介者对象的getMessage
      		this.GetMediator().GetMessage(stateChange, this.name);
      

中介者抽象类

  • 中介者抽象类:提供注册方法,得到消息,发送消息。

    • 具体中介者:存:两个Map

      • HashMap<String, Colleague> colleagueMap; 放 colleagueName 和 具体的同事对象

      • HashMap<String, String> interMap 存: 如闹钟:Alarm,colleagueName

        • colleague instanceof Alarm 进行判断
      • 获取消息接口,写具体的流程

        		//处理闹钟发出的消息
        		if (colleagueMap.get(colleagueName) instanceof Alarm) {
        			if (stateChange == 0) {
        				((CoffeeMachine) (colleagueMap.get(interMap
        						.get("CoffeeMachine")))).StartCoffee();
        				((TV) (colleagueMap.get(interMap.get("TV")))).StartTv();
        			}
        
  • 测试:

    		alarm.SendAlarm(0);
    		//最终调用
    		this.GetMediator().GetMessage(stateChange, this.name);
    

4. 解释器

  1. 先输入表达式的形式,比如 a+b+c-d+e
  2. 在分别输入a ,b, c, d, e 的值

正则表达式解析

终结 非终结

AbstractExpression: 抽象表达式

  • Terminal: 为终结符表达式,聚合父类

    • 加法表达式
    • 减法表达式
  • NonTermial: 为非终结符表达式

  • 抽象类 Expression,抽象方法

    int interpreter(HashMap<String, Integer> var)
    
    • 变量解析器:VarExpression

      var.get(this.key)
      
    • 字符解析器:SymbolExpression

      构造:SymbolExpression(Expression left, Expression right)
      
      • AddExpression

        super.left.interpreter(var) + super.right.interpreter(var);
        

计算器类

Stack<Expression>

right = new VarExpression(String.valueOf(charArray[++i]));

stack.push(new AddExpression(left, right));

left = stack.pop();

获取输入

(new BufferedReader(new InputStreamReader(System.in))).readLine();

SpelExpressionParser

  • Spring框架
		//创建一个 Parser 对象
		SpelExpressionParser parser = new SpelExpressionParser();

		//通过 Parser 对象 获取到一个Expression对象
		//会根据不同的  Parser 对象 ,返回不同的 Expression对象
		Expression expression = parser.parseExpression("10 * (2 + 1) * 1 + 66"); //96
		int result = (Integer) expression.getValue();

  • Expression
    • CompositeStringExpression
    • LiteralExpression
    • SpelExpression 真实返回的

parser.parseExpression 方法,发生了 依赖

  • ExpressionParser
    • abstract class TemplateAwareExpressionParser
      • SpelExpressionParser extends 上面
      • InternalSpelExpressionParser extends 上面

5. 迭代器

计算机学院系=> 数组存

信息工程学院系=> 集合存

提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素

  • 不暴露其内部的结构
public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {}
}
  • Iterator 怎么迭代

    • 计算器学院 迭代器。实现迭代器类,里面定义数组,重写:hasNext 和 next
    • 信息工程学院 迭代器
  • 学院接口 真正的数据

    public Iterator  createIterator();
    public void addDepartment;
    
    • 计算机

      new ComputerCollegeIterator(departments); //使用 数组 创建迭代器
      
    • 信息工程

  • 输出类

    List<College> collegeList; //接收list,list里是学院对象
    
    college.createIterator();//对象 创建迭代器,然后在遍历
    
    		while(iterator.hasNext()) {
    			Department d = (Department)iterator.next();
    			System.out.println(d.getName());
    		}
    
    //College 是接口,所以 可以放 各种学院类
    

ArrayList

List<String> a = new ArrayList<>();
a.add("jack");

Iterator itr = a.iterator();

while (itr.hasNext()) {
	itr.next()
}
  • List 充当了 聚合接口

    • ArrayList 相当于 计算机学院。

       //相当于 计算机学院
      

public class ArrayList extends AbstractList
implements List{
//Object相当于 department
transient Object[] elementData;

   public Iterator<E> iterator() {
       	//Itr是 内部类,所以 无需 聚合 object数组,而是直接使用的
        return new Itr();
   }
}
```
  • Itr 计算机学院的迭代器,会具体实现:hasNext 和 next

List子类

  • LinkedList
  • ArrayLinkedList
  • Vector

- 内部类Itr 充当具体实现迭代器Iterator 的类, 作为ArrayList 内部类
- List 就是充当了聚合接口,含有一个iterator() 方法,返回一个迭代器对象
- ArrayList 是实现聚合接口List 的子类,实现了iterator()
- 迭代器模式解决了 不同集合(ArrayList ,LinkedList) 统一遍历问题

6. 备忘录

new出另外一个对象出来,再把需要备份的数据放到这个新对象,

  • 但这就暴露了对象内部的细节。

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

  • 备忘录类 和 原始类 一样的属性。

  • 原始类 提供一个 创建 备忘录的方法 和 从备忘录获取 属性的方法

    	//因此编写一个方法,返回 Memento
    	public Memento saveStateMemento() {
    		return new Memento(state);
    	}
    	
    	//通过备忘录对象,恢复状态
    	public void getStateFromMemento(Memento memento) {
    		state = memento.getState();
    	}
    
  • 守护者类:就是保存一个list,你要传递 下标,才能取到 对象 回复。

7. 观察者

  • 天气预报服务,自己的项目,百度 都要用。

  • 主题接口:有 注册 移除 观察者,和 通知所有观察者的接口

    • 主题实现类: 维护观察者集合。WeatherData 包含最新的天气信息

      ArrayList<Observer> observers;
      
      	//遍历所有的观察者,并通知
      	@Override
      	public void notifyObservers() {
      
      		for(int i = 0; i < observers.size(); i++) {
      			observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
      		}
      	}
      //另外 还有 添加,删除 订阅者的方法
      
  • 观察接口 Observer,提供更新的方法

    • 观察实现,就是 自己的公告,百度,要接入的
    • 因为:主题实现类,会 调用 这个方法(update),所以 这里实现即可。

Observable

  • jdk的
  • 没有继承接口,类和接口 放在一起了。
public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;
    //有 增 删除,统一 一个,通知所有
}

//观察者接口为:
public interface Observer {

    void update(Observable o, Object arg);
}
  • 使用
public class Weather extends Observable {

    public Weather() {
        // changed = true; 说明已经改变,为了 源码过校验,执行方法
        setChanged();
    }
}

public class BaiduSite implements Observer {
    @Override
    public void update(Observable o, Object arg) {
    }
}

       	//创建 气象局
       	Weather o=new Weather();
		//观察者
        BaiduSite b =new BaiduSite();
		//添加
        o.addObserver(b);
		//通知 观察者
        o.notifyObservers("张三");

8. 状态

解决对象在多种状态转换时,需要对外输出不同的行为的问题。

状态和行为是一一对应的,状态之间可以相互转换。

不能抽奖

  • 扣除50积分,可以抽奖
    • 未中奖,变为 不能抽奖
    • 10% 会中奖 发放奖品
      • 奖品 >0 变为不能抽奖
      • 奖品==0 奖品领完

状态子类

  • 状态接口3个方法。

    • 每个具体的状态实现 对应的接口

    • 并且 有活动类的依赖,改变活动类的接口

      	 // 初始化时传入活动引用,扣除积分后改变其状态
          RaffleActivity activity;
          
          //扣除积分后,改变状态
      	activity.setState(activity.getCanRaffleState());
      
  • 具体为:

    • 不能抽奖(扣减积分),
    • 可以抽奖(抽奖方法),
    • 发放奖品(发奖方法),
    • 奖品售完(没有也行)

活动类

  • 活动类 activity

    • 定义,状态变量,并且创建 所有状态 实现类
    	// state 表示活动当前的状态,是变化
        State state = null;
        
        // 四个属性,表示四种状态
        State noRafflleState = new NoRaffleState(this);
        State canRaffleState = new CanRaffleState(this);
    
    	//有 扣积分 和 抽奖方法(抽中,发奖品)。
    	//因为 其他状态类,都依赖了 此类,所以 这里的方法,其他类 也可以用
    

完善

  • 比如接口有多个方法:

    • 电审,电审失败,
    • 定价发布,
    • 接单,无人接单失效,
    • 付款,支付失效,
    • 反馈
  • 写一个 抽象类继承此 接口,作为中间层

    • 其他状态类,都继承此接口:
    • 订单生成
      • 已审核
      • 已发布
    • 待付款
      • 已付款
    • 已完结
    • 流程类,也继承此 中间层。然后依赖,此状态接口(顶层的)

9. 策略

  • 让算法的变化独立于使用算法的客户

  • 核心:有原来的 继承,转换为 聚合 或 组合。

  • 就是 行为 和 实体类 分开,实体类依赖行为。

    • 行为是:根据不同的实体类,所变化的
  • 鸭子 抽象类,依赖 飞翔的行为。飞翔的方法,使用行为实现。提供了setFlyBehavior

    • 北京
    • 玩具
    • 野鸭 继承鸭子,实现抽象类, new GoodFlyBehavior()
      • setFlyBehavior(new NoFlyBehavior()); ,可以改变其 行为
  • 飞翔。定义接口,多个实现类

    • 不会飞
    • 飞的坏
    • 飞的好
  • 叫声

    • 不会叫
    • 呱呱叫

Arrays排序

		//数组
		Integer[] data = { 9, 1, 2, 8, 4, 3 };
		// 实现降序排序,返回-1放左边,1放右边,0保持不变
		

		// 1. 实现了 Comparator 策略接口 , 匿名类 对象 new Comparator<Integer>(){..}
		// 2. public int compare(Integer o1, Integer o2){} 指定具体的处理方式

		Comparator<Integer> comparator = new Comparator<Integer>() {
			public int compare(Integer o1, Integer o2) {
				if (o1 > o2) {
                    //如果返回1 是升序,这里是 降序
					return -1;
				} else {
					return 1;
				}
			};
		};
		
		//方式1 
		Arrays.sort(data, comparator);
		
		Arrays.toString(data) // 降序排序
		//方式2- 同时lambda 表达式实现 策略模式
		Integer[] data2 = { 19, 11, 12, 18, 14, 13 };
		
		Arrays.sort(data2, (var1, var2) -> {
			if(var1.compareTo(var2) > 0) {
				return -1;
			} else {
				return 1;
			}
		});
		
		Arrays.toString(data2);
  • sort方法
		// 说明
		 * public static <T> void sort(T[] a, Comparator<? super T> c) {
		        if (c == null) {
		            sort(a); //默认方法
		        } else { 
		            if (LegacyMergeSort.userRequested)
		                legacyMergeSort(a, c); //使用策略对象c
		            else
		            	// 使用策略对象c
		                TimSort.sort(a, 0, a.length, c, null, 0, 0);
		        }
		    }

@FunctionalInterface
public interface Comparator<T> {
}

10. 模板方法

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,

  • 使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤

  • 抽象类制作豆浆

    		select(); //本抽象类实现
    		addCondiments(); //是个 抽象方法
    		soak();
    
    • 花生都加,原料加 花生。

钩子方法

		if(customerWantCondiments()) {
			addCondiments();
		}
		
			//钩子方法,决定是否需要添加配料
		boolean customerWantCondiments() {
			return true;
		}
  • 原味豆浆,重写钩子方法,返回false,不会加 其他的东西。

IOC

  • ConfigurableApplicationContext 的 refresh 方法
    • onRefresh 和 postProcessBeanFactory 都是钩子方法

AbstractRefreshableConfigApplicationContext

  • 抽象类类,也是子类,同样实现了。这个两个方法。其子类:
  • ClassPathXmlApplicationContext
  • FileSystemXmlApplicationContext 提供给别人使用

11. 访问者

男人和女人,对歌手进行测评 成功、失败

动作抽象类

  • 动作 抽象类,有方法 得到男的 和 女的评价。

  • 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素

    	//得到男性 的测评
    	public abstract void getManResult(Man man);
    
    • 成功 评价 子类 (实现方法:男人评价成功,女人评价成功)
    • 失败 评价 子类
  • 改进版,上面动作抽象类,依赖的是 具体子类,也可以依赖父类

    • 但 依赖父类,方法没有了 纠错的功能
        public void getManResult(Person man) {
            if (man instanceof Man){
                System.out.println(" 男人给的评价该歌手很成功 !");
            }
        }
    

抽象类 人

  • 提供抽象方法

    	//提供一个方法,让访问者可以访问
    	public abstract void accept(Action action);
    
  • 实现类,女人。无脑调用就行。

    		action.getWomanResult(this);
    
    • 双分派

      //Success类,getManResult(Man man)   在动作抽象类,有方法,通过依赖 具体的 子类,实现区分
      //Woman类,action.getWomanResult(this); 不同的人,建立不同的类,区分
      
  • 数据结构类,就是:创建一个 List,添加,删除,遍历这个list元素。

    		p.accept(action);//真实传递子类。
    		
    		//加入到list里
    		s.attach(new Man());
    		s.attach(new Woman());
    		//真实 传递的为 成功类,就是所有的人评价为成功
    		s.display(success);
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值