本文共 15522 字,大约阅读时间需要 51 分钟。
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式
什么是单例?
保证一个类只会创建一个实例
应用场景:
运行时动态获取类信息
饿汉式
/** * 饿汉式: * 类初始化时,会立即加载对象,线程天生安全,效率高 */public class User { // 存在方法区,不会回收 private static User user = new User(); private User() { } public User getInstance() { return user; }
懒汉式
/** * 懒汉式: * 类初始化时,不会真正创建对象,只有使用时才真正创建对象 */public class User { private static User user; private User() { } public static synchronized User getInstance() { if (user == null) user = new User(); return user; }}
静态内部类
/** * 静态内部类: * 兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射***) */public class User { private User(){ } static class SingletonClassInstance{ private static final User user = new User(); } public static User getInstance() { return SingletonClassInstance.user; }}
枚举方式
/** * 枚举: * 枚举天生就是单例,从JVM提供保障单例,避免反射,缺点没有延迟加载 */public class User { private User() { } public static User getInstance() { return SingletonUserEnum.INSTANCE.getInstance(); } static enum SingletonUserEnum{ INSTANCE; private User user; private SingletonUserEnum() { user = new User(); } public User getInstance() { return this.user; } }}
双重检验锁
/** * 双重检验锁: * 线程安全的单例模式 */public class User { private String userName; private volatile static User3 user3; private User(){ } public User getInstance(){ if (user == null) { synchronized (this) { if (user == null){ user = new User(); } } } return user; }}
如何防止反射漏洞***?
在类里面增加一个 flag,初始值为 false,创建对象后更改为 true,如果为 true,就抛出异常
如何选择单例创建方式?
需要延迟加载,选择静态内部类、懒汉式
不需要延迟加载,选择枚举类、饿汉式
多线程应用首选双重检验锁
什么是工厂模式?
实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂模式
应用场景:
简单工厂
/** * 简单工厂相当于一个工厂有各种产品,用户无需知道具体产品的名称,只需要知道产品对应的参数即可 * 缺点是类型过多不利于扩展维护 */public class CarFactory { public static Car createrCar(String name) { if (name == null || name.equals("")) return null; if (name.equals("比亚迪")) return new BydCar(); if (name.equals("吉利")) return new JiliCar(); return null; }}
工厂方法
/** * 核心工厂不在负责所有产品的创建,而是将具体实现交给子类 */public interface CarFactory { Car createrCar(String name);}class BydFactory implements CarFactory { @Override public Car createrCar(String name) { return new BydCar(); }}class JiliFactory implements CarFactory { @Override public Car createrCar(String name) { return new JiliCar(); }}
什么是抽象工厂模式?
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂
该超级工厂又称为其他工厂的工厂,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类,每个生成的工厂都能按照工厂模式提供对象
应用场景:
/** * 抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品 */public interface Engine { void run();}class EngineA implements Engine{ @Override public void run() { System.out.println("发动机转速快"); }}class EngineB implements Engine { @Override public void run() { System.out.println("发动机转速慢"); }}public interface Chair { void run();}class ChairA implements Chair { @Override public void run() { System.out.println("自动加热"); }}class ChairB implements Chair { @Override public void run() { System.out.println("不能加热"); }}public interface CarFactory { // 创建发动机 Engine createEngine(); // 创建座椅 Chair createChair();}public class JiliFactory implements CarFactory{ @Override public Engine createEngine() { return new EngineA(); } @Override public Chair createChair() { return new ChairA(); }}
简单工厂、工厂方法、抽象工厂小结
什么是代理模式?
代理模式可以控制对象的访问之前之后做一些操作,即 AOP
应用场景:
SpringAOP、事物原理、日志打印、权限控制、远程调用、安全代理
静态代理
/** * 由程序员创建或工具生成代理类的源码,再编译代理类 * 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了 */public interface IUserDao { void save();}public class UserDao implements IUserDao { public void save() { System.out.println("已经保存数据..."); }}代理类public class UserDaoProxy implements IUserDao { private IUserDao target; public UserDaoProxy(IUserDao iuserDao) { this.target = iuserDao; } public void save() { System.out.println("开启事物..."); target.save(); System.out.println("提交事物..."); }}
jdk 动态代理
/** * 是根据类加载器和接口创建代理类 * 通过实现InvocationHandler接口创建自己的调用处理器 * 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类 * 通过反射机制获取动态代理类的构造函数 * 通过构造函数创建代理类实例 * 缺点必须提供接口 */ public class InvocationHandlerImpl implements InvocationHandler { // 目标对象 private Object target; public InvocationHandlerImpl(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开启事务"); // 返回执行结果 Object invoke = method.invoke(target, args); System.out.println("提交事务"); return invoke; } public static void main(String[] args) { IUserDao userDao = new UserDaoImpl(); InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(userDao); // 获得类加载器 ClassLoader classLoader = userDao.getClass().getClassLoader(); // 获得接口 Class [] interfaces = userDao.getClass().getInterfaces(); IUserDao o = (IUserDao) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); o.add(); }}
cglib 动态代理
/** * 利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理 * 不需要提供接口 */public class CglibAutoProxy implements MethodInterceptor { // 目标对象 private Object target; public Object getInstance(Object target){ this.target = target; // 操作字节码生成虚拟子类 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("开启事务"); Object invoke = methodProxy.invoke(target, objects); System.out.println("提交事务"); return invoke; } public static void main(String[] args) { CglibAutoProxy cglibAutoProxy = new CglibAutoProxy(); UserDaoImpl o = (UserDaoImpl) cglibAutoProxy.getInstance(new UserDaoImpl()); o.add(); }}
CGLIB 动态代理与 JDK 动态区别?
JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 InvokeHandler 来处理
而 CGLIB 动态代理是利用 asm 开源包,对代理对象类的 class 文件加载进来,通过修改其字节码生成子类来处理Spring 中:
如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP
如果目标对象实现了接口,可以强制使用 CGLIB 实现 AOP
如果目标对象没有实现了接口,必须采用 CGLIB 库,spring 会自动在 JDK 动态代理和 CGLIB 之间转换
JDK 动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成 final ,final 可以阻止继承和多态
什么是建造者模式?
是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
工厂模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来管理,用来创建复合对象
建造者模式包含以下几个角色:
Builder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建
ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建
Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建
Product:要创建的复杂对象
应用场景:
public class Person { private String head; private String body; private String foot; // 省略get和set }public interface PersonBuilder { void builderHead(); void builderBody(); void builderFoot(); Person builderPerson();}public class ManBuilder implements PersonBuilder { private Person person; public ManBuilder(){ person = new Person(); } public void builderHead() { person.setHead("美国人头部 鼻子尖、长脸、蓝眼睛"); } public void builderBody() { person.setBody("美国人 长得比较高、块头大"); } public void builderFoot() { person.setFoot("美国人 腿长"); } public Person builderPerson() { return person; }}public class PersonDirector { public Person creater(PersonBuilder personBuilder) { personBuilder.builderHead(); personBuilder.builderBody(); personBuilder.builderFoot(); return personBuilder.builderPerson(); } public static void main(String[] args) { PersonDirector personDirector = new PersonDirector(); Person creater = personDirector.creater(new ManBuilder()); System.out.println(creater); }}
什么是模板模式?
完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法,每个步骤的具体实现,由子类完成
应用场景:
// 短信模板public abstract class MsgTemplate { public void sendMsg() { addHeadLog(); httpRequest(); addHeadLog(); } // 开始日志 void addHeadLog() { System.out.println("调用运营商开始。。。"); } abstract void httpRequest(); void addFootLog() { System.out.println("调用运营商结束。。。"); }}public class Liantong extends MsgTemplate { void httpRequest() { System.out.println("联通。。。"); }}// 具体实现细节public class Yidong extends MsgTemplate { void httpRequest() { System.out.println("移动。。。"); }}public class ClientTemplate { public static void main(String[] args) { Yidong yidong = new Yidong(); yidong.sendMsg(); }}
什么是适配器模式
将一个类的接口转换成客户希望的另一个接口,适配器模式让那些接口不兼容的类可以一起工作
应用场景:
public interface JP110VInterface { void connect();}public class JP110VInterfaceImpl implements JP110VInterface { public void connect() { System.out.println("日本110V电源接口"); }}public interface ZN220VInterface { public void connect();}public class ZN220VInterfaceImpl implements ZN220VInterface { public void connect() { System.out.println("中国220V电源接口"); }}public class ElectricCooker { private JP110VInterface jp110VInterface; public ElectricCooker(JP110VInterface jp110VInterface) { this.jp110VInterface = jp110VInterface; } public void cook(){ jp110VInterface.connect(); System.out.println("开启做饭"); }}public class PowerAdpater implements JP110VInterface { private ZN220VInterface zn220VInterface; public PowerAdpater(ZN220VInterface zn220VInterface) { this.zn220VInterface = zn220VInterface; } public void connect() { zn220VInterface.connect(); } public static void main(String[] args) { ZN220VInterface zn220VInterface = new ZN220VInterfaceImpl(); PowerAdpater powerAdpater = new PowerAdpater(zn220VInterface); ElectricCooker electricCooker = new ElectricCooker(powerAdpater); electricCooker.cook(); }}
什么是外观模式?
外观模式门面模式,隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口
应用场景:
// 微信推送消息public interface WeiXinSmsService { public void sendSms(); }public class WeiXinSmsServiceImpl implements WeiXinSmsService{ public void sendSms() { System.out.println("发送微信消息"); }}// 发送邮件public interface EamilSmsService { public void sendSms(); }public class EamilSmsServiceImpl implements EamilSmsService{ @Override public void sendSms() { System.out.println("发送邮件消息"); }}// 支付宝推送消息public interface AliSmsService { public void sendSms();}public class AliSmsServiceImpl implements AliSmsService { @Override public void sendSms() { System.out.println("支付宝发送消息..."); }}public class Computer { AliSmsService aliSmsService; EamilSmsService eamilSmsService; WeiXinSmsService weiXinSmsService; public Computer() { aliSmsService = new AliSmsServiceImpl(); eamilSmsService = new EamilSmsServiceImpl(); weiXinSmsService = new WeiXinSmsServiceImpl(); } public void sendMsg() { aliSmsService.sendSms(); eamilSmsService.sendSms(); weiXinSmsService.sendSms(); }}public class Client { public static void main(String[] args) { new Computer().sendMsg(); }}
什么是原型模式?
原型模式可以用来克隆对象,被复制的实例就是原型,多用于创建复杂的实例,更节约性能。
应用场景:
浅复制和深复制:
只拷贝基本数据类型的数据,对于引用类型数据,仅复制引用,也就是说原型和复制后的对象共享一个变量,如果引用地址的数据发生改变,那么复制出来的对象也会发生改变,我们成为浅复制
深复制是在内存中开辟一块空间存放复制对象
public class Book implements Cloneable{ private String title; private ArrayListlistImg = new ArrayList (); public Book() { super(); } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public List getListImg() { return listImg; } public void setListImg(ArrayList listImg) { this.listImg = listImg; } public void addImage(String img) { this.listImg.add(img); } public void showBook() { System.out.println("----------------start--------------"); System.out.println("title:" + title); for (String img:listImg) { System.out.println("img:" + img); } System.out.println("-----------------end---------------"); } @Override protected Object clone() throws CloneNotSupportedException { Book book = (Book) super.clone(); book.listImg=(ArrayList )this.listImg.clone(); return book; }}public class Client { public static void main(String[] args) throws CloneNotSupportedException { Book book = new Book(); book.setTitle("图书1"); book.addImage("第一章"); book.showBook(); Book book1 = (Book) book.clone(); book1.addImage("第二章"); book1.showBook(); book.showBook(); }}
什么是策略模式?
定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化
应用场景:
package com.kernel.strategy;public interface Strategy { void algorithmInterface();}class StrategyA implements Strategy{ public void algorithmInterface() { System.out.println("级别一处理逻辑"); }}class StrategyB implements Strategy{ public void algorithmInterface() { System.out.println("级别二处理逻辑"); }}class StrategyC implements Strategy{ public void algorithmInterface() { System.out.println("级别三处理逻辑"); }}class Context{ private Strategy strategy; Context(Strategy strategy) { this.strategy = strategy; } void algorithmInterface() { strategy.algorithmInterface(); }}class Client { public static void main(String[] args) { Strategy strategyA = new StrategyA(); Context context = new Context(strategyA); context.algorithmInterface(); context = new Context(new StrategyB()); context.algorithmInterface(); context = new Context(new StrategyC()); context.algorithmInterface(); }}
转载于:https://blog.51cto.com/13559120/2382316