设计模式
Java 中一般认为有 23 种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌握。下面列出了所有的设计模式。需要掌握的设计模式我单独列出来了,当然能掌握的越多越好。
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式。其定义为:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式实现方式:
/**
* @ fileName:eSingleton
* @ description: 饿汉式单例模式
* @ author:wxh
* @ createTime:2022/6/17 19:01
* @ version:1.0.0
*/
public class ESingleton {
public static ESingleton eSingleton = new ESingleton();
public ESingleton() {
}
public static ESingleton getSingleton(){
return eSingleton;
}
}
/**
* @ fileName:LSingleton
* @ description: 懒汉式
* @ author:wxh
* @ createTime:2022/6/17 19:06
* @ version:1.0.0
*/
public class LSingleton {
private static LSingleton lSingleton;
public LSingleton() {
}
//双重校验锁
public static LSingleton getlSingleton(){
if(lSingleton != null){
synchronized (LSingleton.class){
lSingleton = new LSingleton();
}
}
return lSingleton;
}
}
public static void main(String[] args){
//创建单例模式 饿汉式
ESingleton eSingleton = ESingleton.getSingleton();
ESingleton eSingleton2 = ESingleton.getSingleton();
System.out.println(eSingleton == eSingleton2);
//懒汉式
System.out.println(LSingleton.getlSingleton() == LSingleton.getlSingleton());
}
懒汉式(Lazy Initialization)和饿汉式(Eager Initialization)都是单例设计模式的实现方式,用于确保一个类只有一个实例对象。
懒汉式是在第一次使用时才创建实例对象。它的特点是延迟加载,即只有在需要时才会创建实例。懒汉式在多线程环境下可能存在线程安全问题,需要进行额外的线程同步处理。
饿汉式是在类加载时就创建实例对象。它的特点是立即加载,即在程序启动时就会创建实例。因此,饿汉式不存在线程安全问题,但可能会导致资源浪费,因为即使不使用该实例,也会创建并占用内存。
综上所述,懒汉式适用于资源消耗较大、对性能要求较高且不需要立即创建实例的情况;而饿汉式适用于需要确保线程安全、实例创建较为简单且资源消耗较小的情况。
代理模式
静态代理
静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
public interface ITeacherDao {
void teach(); // 授课的方法
}
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
//对象实现类
System.out.println(" 老师授课中 。。。。。");
}
}
/**
* @description: 通过构造将被代理类传进来 调用方法
*
* @return {@link null}
* @author wangxihao
* @email wangxh0108@163.com
**/
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao target; // 目标对象,通过接口来聚合
//构造器
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println("开始代理 完成某些操作。。。。。 ");//方法
target.teach();
System.out.println("提交。。。。。");//方法
}
}
public static void main(String[] args) {
//创建目标对象(被代理对象)
TeacherDao teacherDao = new TeacherDao();
//创建代理对象, 同时将被代理对象传递给代理对象
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
//通过代理对象,调用到被代理对象的方法
//即:执行的是代理对象的方法,代理对象再去调用目标对象的方法
teacherDaoProxy.teach();
}
JDK 动态接口代理
JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。
InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类
的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建
一个符合某一接口的实例,生成目标类的代理对象。
public interface ITeacherDao {
void teach(); // 授课方法
}
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println(" 老师授课中.... ");
}
}
public class ProxyFactory {
//维护一个目标对象 , Object
private Object target;
//构造器 对target 进行初始化 将代理对象传进来
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象 生成一个代理对象
public Object getProxyInstance() {
//说明
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
//1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
//2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
//3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
*/
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;
}
});
}
}
public static void main(String[] args) {
//创建目标对象
ITeacherDao target = new TeacherDao();
//给目标对象,创建代理对象, 可以转成 ITeacherDao
ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
// proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
System.out.println("proxyInstance=" + proxyInstance.getClass());
//通过代理对象,调用目标对象的方法
proxyInstance.teach();
}
CGlib动态代理
CGLib 全称为 Code Generation Library,是一个强大的高性能,高质量的代码生成类库,
可以在运行期扩展 Java 类与实现 Java 接口,CGLib 封装了 asm,可以再运行期动态生成新
的 class。和 JDK 动态代理相比较:JDK 创建代理有一个限制,就是只能为接口创建代理实例,
而对于没有通过接口定义业务方法的类,则可以通过 CGLib 创建动态代理。
public class TeacherDao {
public String teach() {
System.out.println(" 老师授课中 , 我是cglib代理,不需要实现接口 ");
return "hello";
}
}
public class ProxyFactory implements MethodInterceptor {
/**
* <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
* <dependency>
* <groupId>org.ow2.asm</groupId>
* <artifactId>asm</artifactId>
* <version>7.1</version>
* </dependency>
* <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm-commons -->
* <dependency>
* <groupId>org.ow2.asm</groupId>
* <artifactId>asm-commons</artifactId>
* <version>7.1</version>
* </dependency>
* <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm-tree -->
* <dependency>
* <groupId>org.ow2.asm</groupId>
* <artifactId>asm-tree</artifactId>
* <version>7.1</version>
* </dependency>
* <!-- https://mvnrepository.com/artifact/cglib/cglib -->
* <dependency>
* <groupId>cglib</groupId>
* <artifactId>cglib</artifactId>
* <version>3.3.0</version>
* </dependency>
*/
//维护一个目标对象
private Object target;
//构造器,传入一个被代理的对象
public ProxyFactory(Object target) {
this.target = target;
}
//返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
//1. 创建Enhancer对象,用于创建代理类
Enhancer enhancer = new Enhancer();
//2. 设置父类 //需要代理的类target.getClass()
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
}
//重写 intercept 方法,会调用目标对象的方法
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("Cglib代理模式 ~~ 开始");
Object returnVal = method.invoke(target, args);
System.out.println("Cglib代理模式 ~~ 提交");
return returnVal;
}
}
public static void main(String[] args) {
//创建目标对象
TeacherDao target = new TeacherDao();
//获取到代理对象,并且将目标对象传递给代理对象
TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();
//执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
String res = proxyInstance.teach();
System.out.println("res=" + res);
}
工厂设计模式
工厂模式分为工厂方法模式和抽象工厂模式。
工厂方法模式
工厂方法模式分为三种:
简单工厂模式(Simple Factory Pattern):
简单工厂模式又称为静态工厂模式,它通过一个工厂类来封装对象的创建过程。客户端通过工厂类的静态方法来获得所需的产品对象,而无需直接调用具体产品类的构造函数。这种模式的优点是简单易用,但缺点是扩展性较差,新增产品需要修改工厂类的代码。
// 工厂类
public class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equalsIgnoreCase(type)) {
return new ConcreteProductA();
} else if ("B".equalsIgnoreCase(type)) {
return new ConcreteProductB();
} else {
return null;
}
}
}
// 抽象产品类
public abstract class Product {
public abstract void use();
}
// 具体产品类A
public class ConcreteProductA extends Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品类B
public class ConcreteProductB extends Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Product productA = SimpleFactory.createProduct("A");
if (productA != null) {
productA.use();
}
Product productB = SimpleFactory.createProduct("B");
if (productB != null) {
productB.use();
}
}
}
工厂方法模式(Factory Method Pattern):
工厂方法模式定义了一个创建对象的抽象方法,由子类决定实例化哪个类。工厂方法模式将对象的实例化延迟到子类中,使得系统更加灵活。每个具体产品都有对应的工厂类,客户端通过调用工厂类的方法来获得产品对象。这种模式的优点是支持新增产品,但缺点是每增加一个产品就需要新增一个对应的工厂类。
// 抽象工厂类
public abstract class Factory {
public abstract Product createProduct();
}
// 具体工厂类A
public class ConcreteFactoryA extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 具体工厂类B
public class ConcreteFactoryB extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
if (productA != null) {
productA.use();
}
Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
if (productB != null) {
productB.use();
}
}
}
抽象工厂模式(Abstract Factory Pattern):
抽象工厂模式提供一个接口或抽象类来声明一组创建相关产品的方法,具体产品由具体工厂类实现。客户端通过调用工厂类的方法来获得一系列相关的产品对象。抽象工厂模式可以创建多个产品族的产品对象,它的优点是支持新增产品族,但缺点是支持新增产品时需要修改抽象工厂类的代码。
// 抽象工厂类
public abstract class AbstractFactory {
public abstract ProductA createProductA();
public abstract ProductB createProductB();
}
// 具体工厂类1
public class ConcreteFactory1 extends AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂类2
public class ConcreteFactory2 extends AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
// 抽象产品类A
public abstract class ProductA {
public abstract void use();
}
// 具体产品类A1
public class ConcreteProductA1 extends ProductA {
@Override
public void use() {
System.out.println("使用产品A1");
}
}
// 具体产品类A2
public class ConcreteProductA2 extends ProductA {
@Override
public void use() {
System.out.println("使用产品A2");
}
}
// 抽象产品类B
public abstract class ProductB {
public abstract void eat();
}
// 具体产品类B1
public class ConcreteProductB1 extends ProductB {
@Override
public void eat() {
System.out.println("吃产品B1");
}
}
// 具体产品类B2
public class ConcreteProductB2 extends ProductB {
@Override
public void eat() {
System.out.println("吃产品B2");
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
if (productA1 != null) {
productA1.use();
}
ProductB productB1 = factory1.createProductB();
if (productB1 != null) {
productB1.eat();
}
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
if (productA2 != null) {
productA2.use();
}
ProductB productB2 = factory2.createProductB();
if (productB2 != null) {
productB2.eat();
}
}
}
适配器设计模式
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
类的适配器模式
// 目标接口
public interface Target {
void request();
}
// 需要适配的类
public class Adaptee {
public void specificRequest() {
System.out.println("适配者中的业务代码被调用!");
}
}
// 对象适配器
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.request();
}
}
在上述代码中,Adaptee 是需要适配的类,它有一个特定的方法 specificRequest(),而 Target 则是客户端所期望的接口,包含了另一种方法 request()。为了让这两个不兼容的接口能够协同工作,我们创建了一个 Adapter 类,实现了 Target 接口,并将 Adaptee 对象组合进来。在 Adapter 类的 request() 方法中,调用了被适配者的 specificRequest() 方法,从而完成了适配过程。
使用适配器模式可使得系统更加灵活,提高了代码复用性和可维护性。
对象的适配器模式
基本思路和类的适配器模式相同,只是将 Adapter 类作修改,这次不继承 Source 类,而是持有 Source 类的实例,以达到解决兼容性的问题。
接口的适配器模式
接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。
装饰模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。
public interface User {
public void method();
}
public class Usera implements User {
@Override
public void method() {
System.out.println("usera!");
}
}
public class Userb implements User {
@Override
public void method() {
System.out.println("userb!");
}
}
/**
* @ fileName:DecoratorClass
* @ description: 装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例
* @ author:wxh
* @ createTime:2022/6/17 20:22
* @ version:1.0.0
*/
public class DecoratorClass implements User {
private User user;
public DecoratorClass(User user) {
this.user = user;
}
public DecoratorClass() {
}
@Override
public void method() {
System.out.println("之前新增装饰");
user.method();
System.out.println("之后新增装饰");
}
public static void main(String[] args){
Usera usera = new Usera();
DecoratorClass decoratorClass = new DecoratorClass(usera);
decoratorClass.method();
}
}
观察者模式(Observer)
观察者模式很好理解,类似于邮件订阅和 RSS 订阅,当我们浏览一些博客或 wiki 时,经常会看到 RSS 图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。
public interface Observer {
//定义观察者
public void update();
}
class Observera implements Observer{
//定义观察者 添加观察后执行的事件
@Override
public void update() {
System.out.println("observea观察到改动执行");
}
}
class Observerb implements Observer{
//定义观察者 添加观察后执行的事件
@Override
public void update() {
System.out.println("observeb观察到改动执行");
}
}
/**
* @ fileName:subject
* @ description: 操作观察者
* @ author:wxh
* @ createTime:2022/6/17 20:30
* @ version:1.0.0
*/
public interface subject {
//操作观察者的事件
public void add(Observer observer);
public void delete(Observer observer);
//通知所有观察者
public void notifyObserver();
//被观察者自身操作
public void operation();
}
//抽象类 等待业务类继承调用
public abstract class AbstractObserver implements subject {
private Vector<Observer> vector = new Vector<>();
//观察者的事件
@Override
public void add(Observer observer) {
vector.add(observer);
}
@Override
public void delete(Observer observer) {
vector.remove(observer);
}
@Override
public void notifyObserver() {
Enumeration<Observer> elements = vector.elements();
while (elements.hasMoreElements()){
elements.nextElement().update();
}
}
//被观察者自己的操作
@Override
public void operation() {
}
}
/**
* @ fileName:MySubject
* @ description: 被观察者 业务类
* @ author:wxh
* @ createTime:2022/6/17 20:41
* @ version:1.0.0
*/
public class MySubject extends AbstractObserver {
@Override
public void operation() {
System.out.println("执行自己的业务!");
notifyObserver(); //唤醒观察
}
}
public static void main(String[] args){
MySubject mySubject = new MySubject();
mySubject.add(new Observera()); //添加观察者a的事件
mySubject.add(new Observerb());//添加观察者b的事件
mySubject.operation();
}
建造者模式(Builder)
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的 Test 结合起来得到的