1 单例
构造器私有化
用类方法暴露getInstance()
1.1 饿汉
public class Sington1 {
private static Sington1 instance = new Sington1();
private Sington1() {
}
public Sington1 getInstance() {
return instance;
}
}
复制代码
1.2 懒汉
public class Sington2 {
private static volatile Sington2 instance = null;
private Sington2() {
}
public static Sington2 getInstance() {
if (instance == null) {
synchronized (Sington2.class) {
if (instance == null) {
instance = new Sington2();
}
}
}
return instance;
}
}
复制代码
voliatile : 防止指令重排
new 一个对象可以分为三步:
1.分配内存(栈指针指向null),
2.构造器初始化
3.将栈内指针指向对象
,如果没有加 voliatile,可能导致指令重排,第一个线程的 2,3 重排,这时候线程1还在锁里面,线程2进去获取,发现instance!=null(这时候有内存,但是没初始化),这时候存在问题
2 工厂
2.1 简单工厂
public class PhoneFactory {
public Phone makePhone(String phoneType) {
if(phoneType.equalsIgnoreCase("MiPhone")){
return new MiPhone();
}
else if(phoneType.equalsIgnoreCase("iPhone")) {
return new IPhone();
}
return null;
}
}
复制代码
存在问题:
当需要新的 producet的时候,需要修改 Factory 里面的if 判断语句,进行新增,长此以往,Factory将变得很臃肿
2.2 工厂方法
简单来说,就是一个工厂生产一种产品,当需要一个新的产品的时候,就去实现工厂类的接口,创建一个新的工厂类,专门用于生产某种产品。
存在问题:
工厂类爆炸,会生产大量的工厂类用于生产指定的产品
2.3 抽象工厂
将大量的工厂进行细分和抽象,提取其共性
简单理解就是,在工厂方法的时候,如果有要生产 A鼠标 A键盘 A显示器 B鼠标 B键盘 B显示器,需要6个工厂类,而抽象工厂用品牌进行区分 A工厂生产 A鼠标 A键盘 A显示器, B工厂 生产 B鼠标 B键盘B显示器
3 建造者
采用组合的形式,创建一个成员内部类进行组装,代码一看就懂了
public class Computer {
private final String cpu;//必须
private final String ram;//必须
private final int usbCount;//可选
private final String keyboard;//可选
private final String display;//可选
private Computer(Builder builder){
this.cpu=builder.cpu;
this.ram=builder.ram;
this.usbCount=builder.usbCount;
this.keyboard=builder.keyboard;
this.display=builder.display;
}
public static class Builder{
private String cpu;//必须
private String ram;//必须
private int usbCount;//可选
private String keyboard;//可选
private String display;//可选
public Builder(String cup,String ram){
this.cpu=cup;
this.ram=ram;
}
public Builder setUsbCount(int usbCount) {
this.usbCount = usbCount;
return this;
}
public Builder setKeyboard(String keyboard) {
this.keyboard = keyboard;
return this;
}
public Builder setDisplay(String display) {
this.display = display;
return this;
}
public Computer build(){
return new Computer(this);
}
}
//省略getter方法
}
复制代码
Computer computer=new Computer.Builder("因特尔","三星")
.setDisplay("三星24寸")
.setKeyboard("罗技")
.setUsbCount(2)
.build();
复制代码
4 适配器
说白了,就是增加一个中间类,实现两个原本不能互相调用的方法的相互调用
比如:
app中有一个登录接口,现在有一个新的需求,需要记录登录用户的ip信息,这个在原有的接口中并没有这个参数,所以就需要添加一个ip的参数字段。
但是,如果直接在接口上改动,这样之前的app就会出现不兼容的情况,这个时候,就可以使用适配器模式来解决这个问题了,实现新老代码兼容。
5 观察者
用一个 管理者,去管理所有的观察者,有事件发生的时候,遍历管理者列表进行通知,可以进行特定事件特定通知
//观察者
public interface Observer {
public void update();
}
//被观察者
abstract public class Subject {
private List<Observer> observerList = new ArrayList<Observer>();
public void attachObserver(Observer observer) {
observerList.add(observer);
}
public void detachObserver(Observer observer){
observerList.remove(observer);
}
public void notifyObservers(){
for (Observer observer: observerList){
observer.update();
}
}
}
spirng中的事件派发器
Naocs中的异步修改(下线什么这列的)
复制代码
6 责任链
netty,AOP,sentinel, sprngmvc
就是一个方法调用完了,去调用另一个方法
public class FilterChain {
List<Filter> filters = new ArrayList<>();
public FilterChain() {
filters.add(new FilterEgg());
filters.add(new FilterAoBing());
filters.add(new FilterBaiCai());
filters.add(new FilterJiTou());
}
public void processData(String data) {
for (Filter filter : filters) {
filter.doFilter(data);
}
}
}
public class Handler {
public void handlerRequest(Request request) {
// 得到请求的数据
String data = request.getData();
FilterChain filterChain = new FilterChain();
// 处理数据
filterChain.processData(data);
}
}
复制代码
7 包装
是一种组合模式
-
第一步:我们有一个Phone接口,该接口定义了Phone的功能
-
第二步:我们有一个最简单的实现类iPhoneX
-
第三步:写一个装饰器抽象类PhoneDecorate,以组合(构造函数传递)的方式接收我们最简单的实现类iPhoneX。其实装饰器抽象类的作用就是代理(核心的功能还是由最简单的实现类iPhoneX来做,只不过在扩展的时候可以添加一些没有的功能而已)。
-
第四步:想要扩展什么功能,就继承PhoneDecorate装饰器抽象类,将想要增强的对象(最简单的实现类iPhoneX或者已经被增强过的对象)传进去,完成我们的扩展!
// 装饰器,实现接口
public abstract class PhoneDecorate implements Phone {
// 以组合的方式来获取默认实现类
private Phone phone;
public PhoneDecorate(Phone phone) {
this.phone = phone;
}
@Override
public void call() {
phone.call();
}
}
复制代码
8 策略
内部还是组合模式
9 模板方法
重写子类的方法,在模板方法中会去调用该方法
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戏
initialize();
//开始游戏
startPlay();
//结束游戏
endPlay();
}
}
复制代码
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
复制代码
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
复制代码
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
复制代码
- 把公共的代码抽取出来,如果该功能是不确定的,那我们将其修饰成抽象方法。
- 将几个固定步骤的功能封装到一个方法中,对外暴露这个方法,就可以非常方便调用了。
AQS中 tryAcquire 重写,会在 acquire 中调用
10 代理
10.1 静态代理
说白了就是组合
10.2 动态代理
package 代理模式.动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class serviceProxy implements InvocationHandler {
private Object object;
public serviceProxy(Object object) {
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("准备代理");
Object invoke = method.invoke(object, args);
System.out.println("完成代理");
return invoke;
}
}
复制代码
public class Test {
public static void main(String[] args) throws Throwable {
service service = new service();
serviceProxy serviceProxy = new serviceProxy(service);
serviceInterface ser = (serviceInterface) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), serviceProxy);
ser.send("123213");
}
}
复制代码
Proxy.newProxyInstance()返回一个代理对象,其中包括了代理对象、被代理对象
底层是通过jvm指令去生成代理对象的字节码,而后利用传入的 classloader 进行转载进而生成代理对象的类对象,最后通过发射获取构造器constractor创建代理对象的实例
代理模式和装饰者模式区别
功能上面完全一样,都是为了增强原有的功能,如果是静态代理的话,连代码都一样。
设计模式应该从设计层面进行拆分,增强原有功能无非是 继承 和 组合
代理模式 注重的是隔离,只能通过代理对象去访问被代理对象
装饰者模式注重的是拓展,一个方法下面可以实现更多的功能
(参考知乎的一个说法,不过这样子AOP就好像是装饰者模式)
参考
3y