第七章 23种所有设计模式

23种设计模式

一 单例模式

一共有8种单例方式

1  Yunyun yy = Yunyun.getInstance(); //推荐方法,有调用即初始化小瑕疵
方法:构造方法设为私有,别人只能调用该类getInstance单例实例化
	private static final Yunyun Instance = new Yunyun();
	private Yunyun(){}
	public static Yunyun getInstance() {return Instance;}
2 与1相似用静态块
	private static final Yunyun Instance;
	static{
		Instance = new Yunyun();
	}
3 在1基础上懒加载,用时才初始化 (线程不安全,淘汰)

4 3基础上再 synchronized Yunyun getInstance()方法 (效率低下,淘汰)

5 3基础上 先判断if(Instance==NULL) 然后 synchronized(Yunyun.class).
	有重排序问题,淘汰

6 经典方案,双重检查中间加锁方案
volatile变量,判断是否null -> synchronized -> 判断null

7 完美方案
定义静态内部类	
	private Yunyun(){}
	private static class ZhaoYunyun{
		private final static Yunyun Instance = new Yunyun();
	}
	public static Yunyun getInstance(){
		return ZhaoYunyun.Instance;
	}
	//JVM保证了线程安全,class Yunyun只加载一次,所以内部类也只加载一次
	//解决了方案1中的调用即初始化问题,加载Yunyun时,内部静态类不会运行
8 最完美方案 (个人感觉不咋地,纯粹装逼)
ThinkInJava中提供了使用枚举单例,枚举无法使用构造方法,还可以防止反序列化
	public enum Yunyun{
		Instance;
	}

	public class test(){
		main(){
			Yunyun.Instance.hasCode();
		}
	}

二 策略模式

个人感觉和接口意义很像,一个业务需求可能有很多种不同具体实现方式。

比如在Spring中以前讲过,BeanPostProcessor是一个接口,提供两个方法。其他不同类不同方式的实现这一个标准接口的两个方法,实现AOP这些功能,就是策略模式

Comparator 排序器。他本身不知道我们究竟会使用什么参数,什么比较规则来排序。所以他提供这个接口让我们自定义重写,实现自己需要的排序规则,这也是策略模式。

工厂模式

主要是工厂方法和抽象工厂

简单工厂

简单工厂可扩展性很差,不推荐,也不属于23种设计模式内。

public class MeetingFactory{
	public Boy createBoy(){
		return new Boy();
	}
	public Man createMan(){
		return new Man();
	}
	//可扩展性很差
}

三 工厂方法

public interface Product(){
	public void use();
}

public interface Factory{
	public Product createProduct();
}

public class foodFactory implement Factory{
	@Override
	public Product createProduct(){
		return new Food();
	}
}

public class Food implement Product{
	@Override
	public void use(){
		System.out.println("I am food");
	}
}

工厂方法就是对每个新生产对象对应一个工厂

四 抽象工厂

public abstract class Food{
	abstract void printName();
}

public abstract class Weapon{
	abstract void shoot();
}

public abstract class AbstractFactory{
	abstract Food createFood();
	abstract Weapon createWeapon();
}

//把工厂和要生产的对象全部抽象化,这样可以实例化多个不同的工厂,
//多个不同的调用对象,可扩展性很好。

抽象工厂总结:
抽象工厂很容易扩展产品族。新写一个AbstractFactory实现类即可创建新的产品。但是有一大弊端,当我们在AbstractFactory新增一个方法时,所有该工厂实现类都要全部重新添加该方法,违反了开放封闭的原则。

抽象工厂和工厂方法区别?

抽象工厂是工厂方法的衍生,但不是就比工厂方法好。抽象工厂是在工厂方法的基
上同时对多个工厂又封装了一个整体工厂如上AbstractFactory。 在工厂方法中就
会有FoodFactroy和ProductFactroy,而在抽象方法中只有一个AbstractFactory
抽象工厂利于直接创建新的产品族,但是如果封装的这个AbstractFactory有新的对
象需要添加,所有实现这个AbstractFactory都需要重写。工厂方法缺点则是来一个
对象就需要一个工厂,产生的工厂数量太多。两者方法根据业务各自选择。

五 门面模式

内部关系复杂,一个门面来封装所有内部之间的关系(多个接口全部封装到一个门面
类中)给外部调用。

在Tomcat源码中,封装connector模块的request类就是门面模式

六 调停者模式

内部关系复杂,通过一个调停者使得所有内部之间不再交集,通过调停者来调节内
部关系。

如消息中间件MQ

调停者模式和门面模式可以是同一个对象

七 装饰者模式

一个对象想在另一个对象原有的基础上添加一些新的方法。

如果用extend,两者耦合度太高,加一次方法就需要继承一次,扩展性很差。

所以新的类中注入原有对象的变量,在新类的方法下调用原有对象的方法然后加入
自己需要的新装饰逻辑

应用:
这不就是Spring autowire变量注入后,通过这个变量写别的类吗。
和AOP思想也很像,只不过AOP是横向切面处理,装饰者是纵向处理业务

八 责任链模式

创建chain类,链中依次执行各个类处理

interface node{
	public boolean execute(Msg m){
		有问题时返回false表示停止向下处理
	}
}

public class chains extends node{
	add//链表之间互相添加
	exectue//处理所有nodes
}

serlvet中Http处理
require 1,2,3顺序执行后
response 3,2,1顺序相应

class HTMLFilter implement Filter{
	@Override
	public boolean doFilter(Request request,Response response, FilterChain chain){
		1 处理require
		2 递归执行 chain.doFiler会递归执行下一个chain
		3 处理response
	}
}

九 观察者模式

当一个事件被触发则执行某些事情

//大概代码思路
interface Observer{
	public void actionOnWakeUp(wakeUpEvent event);
}

public class Dad implements Observer{
	feed(){
		//逻辑处理
	}
	@Override
	public void actionOnWakeUp(wakeUpEvent event){
		feed();
	}
}

class Child{
	boolean cry = false;
	List<Observer> observers = new ~;
	wakeUp(){
		//wakeUP事件触发,遍历list处理observers所有actionOnWakeUp
	}
}

public class wakeUpEvent{
	long time;
	String location;
	Child source;
}

十 组合模式

树状图结构专用

leaf extends Node{
	print();
}
Branch extends Node{
	List<Node> lists;
	print();
	add(Node n);
}

十一 享元模式

池概念,如线程池,常量池等,重复使用不实例化新对象

十二 代理模式

静态代理
A 接口{
	move();
}

class B implement A{
	move();
}

class Proxy implement A{
	B;
	move{
		xxx;
		B.move();
		xxx;
	}
}

动态代理
handler implement InvocationHandler{
	@Override
	invoke(Object proxy,Method method, Object[] args){
		根据业务需要进行处理
		method.invoke(object, args);//通过反射调用 被代理类的方法
		return null;
	}
}
//实例化代理对象
newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler)

在第二章Spring中专门见过AOP和动态代理
JDKProxyInvocationHandler接口和Proxy类。 在BeanPostProcessor下利用
Java反射,重写postProcessAfterInitialization干预bean初始化实现的。真实
实现类不在单例池中,而是代理类注册在单例池中。

Cglib: 通过ASM(二进制字节码操作类库)直接修改二进制字节码实现生成动态代理

第十三 迭代器模式

动态扩展容器 list.add(xxx)

boolean hasNext();
xxx next();

十四 访问者模式

结构不变情况下,动态改变对于内部元素的动作

应用:
1 编译器中抽象语法树
accept(visitor) 根据传递的visitor判断是符号visitor还是数字visitor等,执
行不同语法解析操作

2 Cglib原理 ASM也是运用访问者模式
如动态生成字节码
ClassWriter cw = new ~;
ClassReader cr = new ~;
cw.accept(cr,0) //根据传入的cr,运用访问者模式动态生成新字节码

十五 建造者模式

当一个对象构造极其复杂时
把一个对象内部大量初始化变量分批构造
A对象中有a b c d e f g变量
新建B对象构造a b c d
新建C对象构造e f g
这样A对象只需要B和C,分批处理

十六 适配器模式

A和B不兼容,通过C作为一个适配器来协调A和B

Spring中DispatcherServlet适配器,适配请求和相应处理的handler

十七 桥接模式

分离抽象和具体,用聚合方法桥接抽象和具体,避免类爆炸

聚合方式类似autowired注入

这篇文章讲得很好

十八 命令模式

能够执行do,还能撤回undo命令的设计思想
abstract class Command{
	abstract void do();
	abstract void undo();
}

十九 原型模式

就是克隆创建新的对象,调用者不调用构造函数。
往往用于创建对象比较繁琐的场景

class Person implement Cloneable{
	.....
	@Override
	public Object clone(){
		return super.clone()
		//这里是调用Object内部clone方法,克隆内存,==是相等的浅拷贝
	}
}
所以引用类型需要深克隆,不然AB都指向同一引用。当A值修改时,B值也莫名其妙
被改了。但是String不需要深克隆,因为String有常量池,A改了会引向新引用,B
值不变

该小段截取于该网站
在深克隆,可以通过序列化(Serialization)等方式来实现。序列化就是 将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一 个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现 Serializable接口,否则无法实现序列化操作。

二十 备忘录模式

记录状态,便于回滚
记录快照,存盘
class Menento implements Serializable{
	public void save(){
		File f = new File(...);
		Object OutputStream oos = new ~(f);
		oos.write(objects);
	}
	public File load(){
		//加载文件
	}
}

二十一 模版模式

子类继承父类模版后,重写父类方法然后使用

父类仅仅提供一个模版,提供构造函数

二十二 状态模式

根据状态来决定行为

如汽车类有open,close,running,stopped四个方法,在不同状态下。
四个方法有的不能执行,有的必须执行。

二十三 解释器模式

动态脚本解析

总体基本原则

可维护,复用,可扩展,灵活

面向对象六大指导原则

纯死记硬背,个人认为没有什么意义,记住23种设计模式灵活运用最重要

你可能感兴趣的:(JavaWeb基础篇,设计模式)