一、单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
为什么使用单例模式?
1.在设计一些工具类的时候(通常工具类只有工具方法,没有属性)
2.工具类被频繁调用
3.节省重复创建对象所带来的的内存消耗,从而提高效率
实现步骤:
1.构造方法私有化。
2.声明一个当前类对象。
3.给外部提供一个静态方法获取对象实例。
两种实现方式
1.饿汉式:在类加载后,对象被创建,到程序结束后释放。
2.懒汉式:第一次调用获取实例的方法时,对象被创建,到程序结束后释放。
饿汉式实现
/**
* 描述 : 饿汉式,占用内存时间长,提高效率
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 9:43
* @DESCRIPTION :
*/
public class SingletonTest {
public static SingletonTest singleton=new SingletonTest();
private SingletonTest() {
}
public static SingletonTest getSingleton(){
return singleton;
}
public void doSomething(){
System.out.println("开始做某件事");
}
}
懒汉式实现
/**
* 描述 : 懒汉式
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 9:56
* @DESCRIPTION :
*/
public class SingletonLazyTest implements Serializable{
private static final long serialVersionUID = 1L;
/**
* volatile关键字保证变量的一致性
*/
public static volatile SingletonLazyTest singleton = null;
private SingletonLazyTest() {
//防止后续反射调用私有构造方法
if (singleton!=null) {
throw new RuntimeException();
}
}
public static SingletonLazyTest getSingleton() {
//singleton不为空时不必执行
if (singleton == null) {
//同步锁当前类对象
synchronized (SingletonLazyTest.class) {
if (singleton == null) {
singleton = new SingletonLazyTest();
}
}
}
return singleton;
}
public void doSomething(){
System.out.println("懒汉式开始做某事");
}
}
二、模板方法模式
定义一个操作中的算法骨架(把共有部分抽象出来),将一些可变部分的实现延迟到子类中。模板方法可以使得子类可以不改变一个算法结构即可重新定义该算法的某些特定步骤。
抽象类
/**
* 描述 : execute方法具体实现交由子类
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 11:22
* @DESCRIPTION :
*/
public abstract class BaseManager {
public void action(String name,String method){
if ("admin".equals(name)) {
execute(method);
}else {
System.out.println("你不是管理员");
}
}
public abstract void execute(String method);
}
子类
/**
* 描述 :自由实现的execute方法
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 11:30
* @DESCRIPTION :
*/
public class UserManager extends BaseManager {
@Override
public void execute(String method) {
//执行操作前的其他方法,比较数据校验
if ("add".equals(method)) {
System.out.println("执行添加操作");
} else if ("delete".equals(method)){
System.out.println("执行删除操作");
}
}
}
测试类
public class Test {
public static void main(String[] args) {
BaseManager userManager = new UserManager();
userManager.action("admin","add");
}
}
程序运行结果
执行添加操作
Process finished with exit code 0
适用场景:
1.多个子类有共同的方法,并且基本逻辑大致相同
2.重要、复杂的算法,可以把核心逻辑设计成模板方法,其细节实现交由子类。
三、策略模式
定义一系列算法,将每一种算法封装起来并可以互相替换使用
1.一个接口多个实现类,不同的实现独立封装,可以按照运行时需要互相替换,可维护性强。
2.新增接口实现不会影响其他实现类
3.符合开闭原则,对拓展开放,对修改关闭
4.巧用策略模式避免大量的if else代码
策略接口
/**
* 描述 :
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 13:42
* @DESCRIPTION :
*/
public interface BaseService {
void saveData();
}
接口实现类
/**
* 描述 :
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 13:44
* @DESCRIPTION :
*/
public class MySQLServiceImpl implements BaseService {
@Override
public void saveData() {
System.out.println("数据保存在MySQL数据库中");
}
}
/**
* 描述 :
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 13:45
* @DESCRIPTION :
*/
public class OracleServiceImpl implements BaseService{
@Override
public void saveData() {
System.out.println("数据保存在Oracle数据库中");
}
}
抽象类
/**
* 描述 :
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 13:55
* @DESCRIPTION :
*/
public abstract class Save {
private BaseService baseService;
public void setSave(BaseService baseService) {
this.baseService = baseService;
}
public Save() {
}
public void saveData(String data){
System.out.println("校验数据开始");
baseService.saveData();
}
}
抽象类子类
/**
* 描述 :
*
* @AUTHOR SYLIANG
* @DATE 2021/9/2 14:03
* @DESCRIPTION :
*/
public class SaveImpl extends Save {
}
测试类
public class test {
public static void main(String[] args) {
Save saveImpl=new SaveImpl();
saveImpl.setSave(new MySQLServiceImpl());
saveImpl.saveData("shuju");
saveImpl.setSave(new OracleServiceImpl());
saveImpl.saveData("数据");
}
}
程序运行结果
校验数据开始
数据保存在MySQL数据库中
校验数据开始
数据保存在Oracle数据库中
Process finished with exit code 0
四、简单工厂模式
简单工厂模式是由一个工厂对象决定创建哪一个类的实例
电子设备生产接口
public interface Electronic {
void create();
}
生产手机类
public class Phone implements Electronic{
@Override
public void create() {
System.out.println("开始生产手机");
}
}
生产电脑类
public class Computer implements Electronic {
@Override
public void create() {
System.out.println("开始生产电脑");
}
}
工厂类
public class Factory {
public static Electronic get(String type) {
if ("phone".equals(type)) {
return new Phone();
} else if ("computer".equals(type)) {
return new Computer();
}
return null;
}
}
测试类
public class test {
public static void main(String[] args) {
Electronic electronic=null;
electronic = Factory.get("computer");
electronic.create();
electronic=Factory.get("phone");
electronic.create();
}
}
程序运行结果
开始生产电脑
开始生产手机
Process finished with exit code 0
五、适配器模式
将一个类的接口转换成用户希望的另外一个接口,适配器模式使得原本由于接口不兼容不能一起工作的类可以一起工作。类似电脑转接头
对修改关闭对拓展开放
现在有一个电源A接口
public interface PowerA {
void action();
}
电源A的实现类
public class PowerAImpl implements PowerA {
@Override
public void action() {
System.out.println("电源A开始工作");
}
}
一个传入形参为A的work方法
public static void work(PowerA powerA){
System.out.println("开始连接");
powerA.action();
System.out.println("工作结束");
}
后续由于业务拓展,新增一个电源B,但是我们无法将电源B作为实参传入work方法中。这时可以新增一个适配器类实现A接口,重写其方法并在方法中调用B的方法。
接口
public interface PowerB {
void doAction();
}
实现类
public class PowerBImpl implements PowerB {
@Override
public void doAction() {
System.out.println("电源B开始工作");
}
}
适配器类
public class Adapter implements PowerA{
private PowerB powerB;
public void setPowerB(PowerB powerB) {
this.powerB = powerB;
}
@Override
public void action() {
powerB.doAction();
}
}
这时我们就可以在不改变原有代码的情况下,让新加的电源B正常工作
Adapter adapter = new Adapter();
adapter.setPowerB(new PowerBImpl());
work(adapter);
程序运行结果
public static void main(String[] args) {
PowerAImpl powerA = new PowerAImpl();
work(powerA);
Adapter adapter = new Adapter();
adapter.setPowerB(new PowerBImpl());
work(adapter);
}
开始连接
电源A开始工作
工作结束
开始连接
电源B开始工作
工作结束
Process finished with exit code 0
六、装饰者模式
在不影响其他对象的情况下动态给一个对象添加一些额外的职责。如果使用继承,有可能因为组合太多导致类爆炸,衍生无数子类。
假设现在我们想喝饮料,然后来到奶茶店点一杯奶茶,配料可加糖、椰果、珍珠。我们可随意组合制成我们需要的奶茶。
被装饰者的基类(饮料)
/**
* 描述 :被装饰者的基类
*
* @AUTHOR SYLIANG
* @DATE 2021/9/3 14:19
* @DESCRIPTION :
*/
public interface Drink {
String create();
int cost();
}
具体的被装饰者类(奶茶)
/**
* 描述 : 具体的被装饰者类
*
* @AUTHOR SYLIANG
* @DATE 2021/9/3 14:21
* @DESCRIPTION :
*/
public class MilkyTea implements Drink {
@Override
public String create() {
return "制作了一杯原味奶茶";
}
@Override
public int cost() {
return 5;
}
}
装饰者的基类
/**
* 描述 : 装饰者的基类
*
* @AUTHOR SYLIANG
* @DATE 2021/9/3 15:05
* @DESCRIPTION :
*/
public abstract class Decorate implements Drink {
/**
* 要装饰的对象
*/
private Drink drink;
public Decorate(Drink drink) {
this.drink = drink;
}
@Override
public String create() {
return drink.create();
}
@Override
public int cost() {
return drink.cost();
}
}
具体的装饰者类(珍珠)
/**
* 描述 : 珍珠 具体的装饰者类
*
* @AUTHOR SYLIANG
* @DATE 2021/9/3 14:26
* @DESCRIPTION :
*/
public class Pearl extends Decorate {
public Pearl(Drink drink) {
super(drink);
}
@Override
public String create() {
return super.create()+"+珍珠";
}
@Override
public int cost() {
return super.cost()+3;
}
}
具体的装饰者类(椰果)
/**
* 描述 :椰果 具体的装饰者类
*
* @AUTHOR SYLIANG
* @DATE 2021/9/3 14:29
* @DESCRIPTION :
*/
public class Coconut extends Decorate{
public Coconut(Drink drink) {
super(drink);
}
@Override
public String create() {
return super.create()+"+椰果";
}
@Override
public int cost() {
return super.cost()+2;
}
}
具体的装饰者类(糖)
/**
* 描述 : 糖 具体的装饰者类
*
* @AUTHOR SYLIANG
* @DATE 2021/9/3 14:30
* @DESCRIPTION :
*/
public class Sugar extends Decorate {
public Sugar(Drink drink) {
super(drink);
}
@Override
public String create() {
return super.create()+"+糖";
}
@Override
public int cost() {
return super.cost()+1;
}
}
点了一杯加糖加椰果加珍珠的奶茶
public static void main(String[] args) {
Drink milkyTea = new MilkyTea();
Pearl pearl = new Pearl(milkyTea);
Sugar sugar = new Sugar(pearl);
Coconut coconut = new Coconut(sugar);
System.out.println(coconut.create());
//制作了一杯原味奶茶+珍珠+糖+椰果
System.out.println(coconut.cost());
//11 //5+3+1+2
}
程序运行结果
制作了一杯原味奶茶+珍珠+糖+椰果
11
Process finished with exit code 0
七、静态代理模式
为其他对象提供一种代理以控制对这个对象的访问,说白了就是委托别人帮你做某件事,比如让同事帮你带个早餐。
接口
public interface Action {
void doSomething();
}
被代理类
public class UserAction implements Action {
@Override
public void doSomething() {
System.out.println("用户开始工作");
}
}
代理类
public class Proxy {
private Action target;
public void setAction(Action action) {
this.target = action;
}
public void execute(){
System.out.println("代理开始");
target.doSomething();
System.out.println("代理结束");
}
}
测试类
public class Test {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.setAction(new UserAction());
proxy.execute();
}
}
程序运行结果
代理开始
用户开始工作
代理结束
Process finished with exit code 0
八、动态代理模式
静态代理中,我们在代理类声明了被代理对象Action ,此时如果再加一个代理对象,那就必须修改代码了。那可不可以不修改呢?答案是可以的,这时候我们引入动态代理。
- JDK动态代理
接口
public interface Action {
void doAction();
}
接口实现类
public class UserAction implements Action {
@Override
public void doAction() {
System.out.println("用户开始做某件事情");
}
}
public class AdminAction implements Action {
@Override
public void doAction() {
System.out.println("管理开始");
}
}
生成代理对象类
/**
* 描述 : 用于动态生成一个代理对象
* * @AUTHOR SYLIANG
* @DATE 2021/9/6 10:43
* @DESCRIPTION :
*/
public class DynamicProxy implements InvocationHandler {
/**
* 被代理的对象
*/
private Object target;
public Object createTarget(Object target) {
this.target = target;
Object proxy =
Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
return proxy;
}
/**
* 描述: 代理对象需要执行的方法
* @param proxy 代理类对象
* @param method 被代理对象的方法
* @param args 被代理对象方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理开始");
method.invoke(target,args);
System.out.println("动态代理结束");
return null;
}
}
测试类
public static void main(String[] args) {
//UserAction userAction = new UserAction();
DynamicProxy proxy = new DynamicProxy();
//Action target = (Action) proxy.createTarget(userAction);
//target.doAction();
System.out.println("----------------");
AdminAction adminAction = new AdminAction();
Action admin = (Action) proxy.createTarget(adminAction);
admin.doAction();
}
程序运行结果
----------------
动态代理开始
管理开始
动态代理结束
Process finished with exit code 0
- cglib动态代理
被代理类
public class Cat {
public void eat(){
System.out.println("the cat is eating");
}
}
生成代理对象类
public class CglibProxy implements MethodInterceptor {
private Object target;
public Object getInstance(Object target) {
this.target=target;
Enhancer enhancer = new Enhancer();
//设置父类为实例类
enhancer.setSuperclass(this.target.getClass());
//回调方法
enhancer.setCallback(this);
//创建代理对象
Object o = enhancer.create();
return o;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib动态代理开始");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("cglib动态代理结束");
return invoke;
}
}
测试类
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
Cat instance = (Cat)cglibProxy.getInstance(new Cat());
instance.eat();
}
程序运行结果
cglib动态代理开始
the cat is eating
cglib动态代理结束
JDK动态代理与cglib动态代理的比较
- JDK动态代理只能代理实现接口的类,基于接口实现
Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
- cglib动态代理是可以代理普通类,通过子类继承被代理对象的方式实现(所以被代理的类不能被final修改),性能更高,但必须引入相关依赖。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>