模式整合】20秒速记23种设计模式。设计模式7原则,UML类图。创建,结构,行为型。"/>
【设计模式整合】20秒速记23种设计模式。设计模式7原则,UML类图。创建,结构,行为型。
设计模式7原则,UML类图。创建,结构,行为型。速记23种设计模式。
依 里 接 单 开 合 笛
建 工 抽 原 单
适 桥 组 装 享 外 代
责 命 中 解 迭 备
观 状 策 模 访
7原则概述
- 单一职责原则
- 接口隔离原则
- 依赖倒转原则
- 里氏替换原则
- 开闭原则 ocp
- 迪米特法则
- 合成复用原则
依 里 接 单 开 合 笛
依赖倒转
-
接口的依赖
-
同开闭,加功能使用方不变
-
我们发送一个消息,直接调用发送消息的 接口。
- 具体使用的时候,用 Email 发送,那真实参数 就传递Email类
里式替换
-
继承必须确保 超类所拥有的性质
- 在子类中 依然成立
-
增加功能时:把以前的类依赖过来,原逻辑用原来的方法(包一层)。
- 提取父类,使用组合关系。
接口隔离
-
要什么功能实现什么接口
-
接口 已经最小化,不会有 冗余的实现
单一职责
- 汽车在地上跑
- 汽车类,地上跑的方法。
- 极简情况,是一个的类,上面有:地上跑,天上飞的方法。
开闭原则
- 使用方,无需改变。同依赖倒转
- 使用的时候 依赖的是接口。
- 新增图形 继承父类
- 不改变其他类,父类有的方法依然存在。
- 比如:我需要 圆周率非常精确,我就重写父类的方法。
合成复用
尽量使用合成/聚合的方式,而不是使用继承
迪米特法则
- 最少知道原则
直接朋友,我们称出现
-
成员变量,
-
方法参数,
-
方法返回值中的类为直接的朋友,
-
而出现在局部变量中的类不是直接的朋友。
-
陌生的类最好不要以局部变量的形式出现在类的内部。
-
学校 打印 学院的信息,调用 学院的打印
- 而不是:获取到学院的列表(局部变量)。违法了 迪米特
核心思想
-
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代
码混在一起。 -
针对接口编程,而不是针对实现编程。
-
为了交互对象之间的松耦合设计而努力
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 即充当了指挥者角色,同时充当了具体的建造者
- AbstractStringBuilder 已经是建造者,只是不能实例化。建造方 法的实现。
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. 单例
单例的各种实现
- 饿汉式(静态常量) 推荐
- 私有构造
- 创建对象实例
- 提供公有的访问
- 饿汉式(静态代码块)
- 懒汉式(线程不安全)
- 懒汉式(线程安全,同步方法)synchronized
- (无用)懒汉式(线程也不安全,同步代码块)
- 双重检查 推荐
- 静态内部类,创建外部对象 推荐
- 枚举
- CAS AtomicReference 的 compareAndSet
- ConcurrentHashMap 自己设计
静态常量 饿汉式
//饿汉式(静态变量) Singleton
class S {//1. 构造器私有化, 外部能newprivate 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 {//定义 atomicprivate 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指令集操作,只有一步 原子操作INSTANCEpareAndSet(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 HttpControllerpublic 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 巧克力
- Coffee
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 { //是一个装饰者类Decoratorprotected 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)); // 值比较为trueSystem.out.println(x == y ); // 对象比较为 falseSystem.out.println(x == z ); // 同样:Integer.valueOf 为trueSystem.out.println(w == x ); // 和 new相比,为falseSystem.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 {//维护一个目标对象 , Objectprivate Object target;//构造器 , 对target 进行初始化//给目标对象 生成一个代理对象public Object getProxyInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic 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 方法,会调用目标对象的方法@Overridepublic 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})@ResponseBodypublic 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 , 匿名内
部类, 实现了命令接口, 同时也充当命令接收者
- class QueryStatementCallback implements StatementCallback, SqlProvider , 匿名内
-
命令调用者 是 JdbcTemplate , 其中execute(StatementCallback action) 方法中,
- 调用action.doInStatement 方法. 不同的 实现 StatementCallback 接口的对象,对应不同
的doInStatemnt 实现逻辑
- 调用action.doInStatement 方法. 不同的 实现 StatementCallback 接口的对象,对应不同
-
不同之处在于,正规的 命令模式:命令接收者(士兵),不会实现命令的。
-
此处的命令调用者(指挥者,将军):还充当了 整合接收者。
-
将军(调用者):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);
//抽象接口的实现//调用的中介者对象的getMessagethis.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. 解释器
- 先输入表达式的形式,比如 a+b+c-d+e
- 在分别输入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"); //96int result = (Integer) expression.getValue();
- Expression
- CompositeStringExpression
- LiteralExpression
- SpelExpression 真实返回的
parser.parseExpression 方法,发生了 依赖
- ExpressionParser
- abstract class TemplateAwareExpressionParser
- SpelExpressionParser extends 上面
- InternalSpelExpressionParser extends 上面
- abstract class TemplateAwareExpressionParser
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出另外一个对象出来,再把需要备份的数据放到这个新对象,
- 但这就暴露了对象内部的细节。
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
-
备忘录类 和 原始类 一样的属性。
-
原始类 提供一个 创建 备忘录的方法 和 从备忘录获取 属性的方法
//因此编写一个方法,返回 Mementopublic Memento saveStateMemento() {return new Memento(state);}//通过备忘录对象,恢复状态public void getStateFromMemento(Memento memento) {state = memento.getState();}
-
守护者类:就是保存一个list,你要传递 下标,才能取到 对象 回复。
7. 观察者
-
天气预报服务,自己的项目,百度 都要用。
-
主题接口:有 注册 移除 观察者,和 通知所有观察者的接口
-
主题实现类: 维护观察者集合。WeatherData 包含最新的天气信息
ArrayList<Observer> observers;//遍历所有的观察者,并通知@Overridepublic 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 {@Overridepublic 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(var1pareTo(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); //使用策略对象celse// 使用策略对象cTimSort.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);
更多推荐
【设计模式整合】20秒速记23种设计模式。设计模式7原则,UML类图。创建,结构,行为型。
发布评论