设计模式分类
GoF提出的设计模式总共有23种
根据目的准则分类,分为三大类。
创建型设计模式,共5种:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
结构型设计模式,共7种:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型设计模式,共11种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
另外,随着设计模式的发展也涌现出很多新的设计模式:它们分别是规格模式、对象池模式、雇工模式、黑板模式和空对象模式等。
创建型:
/**
* 工厂方法模式 --- 工厂类通过类方法创建产品
* 使用场景: 频繁创建对象,后续可能存在修改实例化
* 目的:可以隐藏创建过程(实例化过程),实例化处与调用方解耦
* 带来的好处: 后期如果存在实例化改造,只需要在工厂类中处理
* */
public class GDComputerFactory extends ComputerFactory {
@Override
public <T extends Computer> T createComputer(Class<T> clz) {
Computer computer = null;
String className = clz.getName();
try {
computer = (Computer) Class.forName(className).newInstance();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) computer;
}
}
public abstract class ComputerFactory {
public abstract <T extends Computer> T createComputer(Class<T> clz);
}
public abstract class Computer {
public abstract void start();
}
public class LenovoComputer extends Computer {
@Override
public void start() {
System.out.println("LenovoComputer is out of date.");
}
}
/**
* builder 模式
* 使用场景:
* 创建对象过于复杂,需要创建独立于对象的组成部分以及它们的装配方式
* 相同的方法,不同的执行顺序,产生不同的事件结果
* 多个部件或零件都可以被装配到一个对象中,但是产生的运行结果又不相同时
* 产品类非常复杂,或者产品类中的调用顺序不同而产生不同的效能
*
* 在创建一个复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化
* */
public abstract class Builder {
public abstract void buildCpu(String cpu);
public abstract void buildMainboard(String mainBoard);
public abstract void buildRam(String ram);
public abstract Computer create();
}
public class Director {
Builder mBuild = null;
public Director(Builder build) {
mBuild = build;
}
public void setBuild(Builder build) {
mBuild = build;
}
public Computer createComputer(String cpu, String mainboard, String ram) {
mBuild.buildMainboard(mainboard);
mBuild.buildCpu(cpu);
mBuild.buildRam(ram);
return mBuild.create();
}
}
public class MoonComputerBuilder extends Builder {
private Computer mComputer = new Computer();
@Override
public void buildCpu(String cpu) {
mComputer.setmCpu(cpu);
}
@Override
public void buildMainboard(String mainBoard) {
mComputer.setmMainboard(mainBoard);
}
@Override
public void buildRam(String ram) {
mComputer.setmRam(ram);
}
@Override
public Computer create() {
return mComputer;
}
}
public class Computer {
private String mCpu;
private String mMainboard;
private String mRam;
public String getmCpu() {
return mCpu;
}
public void setmCpu(String mCpu) {
this.mCpu = mCpu;
}
public String getmMainboard() {
return mMainboard;
}
public void setmMainboard(String mMainboard) {
this.mMainboard = mMainboard;
}
public String getmRam() {
return mRam;
}
public void setmRam(String mRam) {
this.mRam = mRam;
}
}
反向编译
JAD Java Decompiler Download Mirrorhttps://varaneckas.com/jad/jad [*.class]
高频
单例
通过静态类,静态方法实现单例。反射破坏单例
/**
* 正常调用方法或者 多线程都能反正单例
* 反射会破坏单例
*/
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton() {
}
// static 为了使单例的空间共享,保证这个方法不会被重写、重载
// final 当某个类的整体定义为final时,就表明了你不能打算继承该类,而且也不允许别人这么做。即这个类是不能有子类的。
public static final LazyInnerClassSingleton getInstance() {
return LazyHolder.instantce;
}
private static class LazyHolder {
private static final LazyInnerClassSingleton instantce = new LazyInnerClassSingleton();
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class LazyInnerClassSingletonTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> clazz = LazyInnerClassSingleton.class;
Constructor c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Object o1 = c.newInstance();
Object o2 = c.newInstance();
Object o3 = LazyInnerClassSingleton.getInstance();
// new 三次,犯了原则性错误, 无法实现单例
System.out.println(o1 == o2);
System.out.println(o2 == o3);
System.out.println(o3 == o1);
}
}
采用 Enum 不能反射构造,实例化,static 特性,完美实现单例
/**
*ENUM static 实例化保证对象单例
*反射不能实例化, JDK 对Enum newInstance throw
*推荐通过 enum 实现单例
**/
enum EnumSingleton {
// static object
INSTANCE,
AAAA;
private Object data; // share in enum
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
static
{
INSTANCE = new EnumSingleton("INSTANCE", 0);
AAAA = new EnumSingleton("AAAA", 1);
$VALUES = (new EnumSingleton[] {
INSTANCE, AAAA
});
}
@CallerSensitive
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
// intercept 拦截 Enum 实例化
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
Threadlocal 能够保证在本线程内单例, 反射也会破坏。实现原理,hasmap,key为currentThread
public class testthreadlocal {
public static class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
new ThreadLocal() {
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton() {
}
public static ThreadLocalSingleton getInstance() {
return threadLocalInstance.get();
}
}
public static void main(String[] args) {
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
Class clazz = ThreadLocalSingleton.class;
try {
Constructor c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
try {
Object o1 = c.newInstance();
System.out.println("reflect --> " + o1);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Thread t1 = new Thread(new ExectorThread());
Thread t2 = new Thread(new ExectorThread());
t1.start();
t2.start();
System.out.println("End");
}
}
通过clone方式 实现prototype,优雅地复制对象
/**
* 原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
* 原型模式主要适用于以下场景:
* a). 类初始化消耗资源较多。
* b). 使用 new 生成一个对象需要非常烦琐的过程(数据准备、访问权限等)。
* c). 构造函数 较复杂。
* d). 在循环体中产生大量对象。
* */
package main.prototype;
import java.io.*;
import java.util.Date;
public class QiTianDaSheng extends Monkey implements Cloneable, Serializable {
public JinGuBang jinGuBang;
public QiTianDaSheng() {
this.birthday = new Date();
this.jinGuBang = new JinGuBang();
}
// 我们已经清楚Object.clone()是protected方法。这说明,该方法可以被同包(java.lang)下以及它(java.lang.Object)的子类访问
@Override
protected Object clone() throws CloneNotSupportedException {
return this.deepClone();
}
public Object deepClone() {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
QiTianDaSheng copy = (QiTianDaSheng) ois.readObject();
copy.birthday = new Date();
return copy;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
public QiTianDaSheng shallowClone(QiTianDaSheng target) {
QiTianDaSheng copy = new QiTianDaSheng();
copy.height = target.height;
copy.weight = target.weight;
copy.jinGuBang = target.jinGuBang;
copy.birthday = target.birthday;
return copy;
}
}
JDK ProxyGenerator 动态生成代理类.class
step1: 生成代理类class 字节码
> 保存 className,interfaces,accessFlags
> 将 hasCode,equals, toString 加入到 proxyMethods (Map<String, List<ProxyMethod>>
> 将被代理(目标)对象中的Methods加入到proxyMethods
> 将<init> <proxyMethods> <cinit> 加入到methods(List<MethodInfo>)中
> 添加常量信息到ConstantPool
>> className、"java/lang/reflect/Proxy"、interfaces 对应的包路径名
> 开始写入数据
>> 先写入4个字节魔鬼数字,用来确定是否能被虚拟机接受的class文件
>> 次版本号0, 主版本号49
>> 写入常量ConstantPool IndirectEntry(tag index0 index1(tag 9(FiledRef) 10(MethodRef) 11(InterfaceMethodRef) 12(NameAndType)))
>> accessFlags
>> cp中 className、"java/lang/reflect/Proxy"对应 index
>> 接口数量、接口对应的cp index
>> 字段数量、FieldIfno
>> methods, MethodInfo
>> 生成代理类 自身属性数量 0
>> 将 ByteArrayOutputStream 转成 ByteArray
step2: 通过 Proxy static native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len); 加入到jvm中
注意:
为了保证 生成 class 唯一,使用了
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
ConstantPool 插入IndirectEntry不重复的关键在于实现了 equals方法
public boolean equals(Object var1) {
if (var1 instanceof ConstantPool.IndirectEntry) {
ConstantPool.IndirectEntry var2 = (ConstantPool.IndirectEntry) var1;
if (this.tag == var2.tag && this.index0 == var2.index0 && this.index1 == var2.index1) {
return true;
}
}
return false;
}
CGLIB 和JDK 代理 生成class文件区别
No1. CGLIB 采用 extends,JDK 采用 interfaces
No2. CGLIB采用 fastClass(index ,c1(代理类), c2(被代理类), f1, f2) 方式生成class文件,JDK 采用 ProxyGenerator生成class文件
生效效率: jdk高
执行效率: cglib高
委派模式 (delegate pattern) 不属于GoF 23中设计模式。
正则表达式:
获取文件后缀 和 获取 文件名
String regex = "([a-zA-z]+)$"; // 只匹配 符号后面的内容
String imageName = "E://hello//abc.document";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(imageName);
// boolean b = m.matches();
if (m.find()) {
System.out.println("1111-> " + m.groupCount() + m.group(1));
} else {
System.out.println("not found...");
}
String regex = "//([a-zA-z0-9_]+)"; // 获取文件名
String imageName = "E://hello//abc_123.document";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(imageName);
int startIndex = 0;
while(m.find(startIndex)) {
for (int i = 0; i < m.groupCount(); i++) {
System.out.println("============" + startIndex + "============");
System.out.println((i + 1) + " ======== " + m.group(i + 1));
System.out.println("========================");
}
startIndex = m.end();
}