什么是设计模式?
设计模式是软件开发过程中经常遇到的问题的通用解决方案。类似于前人总结的经验,遇到相似问题的时候有个参考。
设计模式七大基本原则?
- 单一职责:一个类应该只作一件事情。将功能分为小的独立的单元。
- 开放封闭原则:对扩展开放,对修改关闭。
- 里氏替换原则:任何一个父类出现的地方,都可以用子类替换,而不会导致错误或者异常。
- 依赖倒置:高层模块不应该依赖于底层,应该依赖于抽象,实现解耦。
- 接口隔离:一个类不应该强迫它的客户端依赖于它们不需要的方法,接口应该小而专注,不应该包含多余的方法。
责任链模式?
- 一种行为型设计模式,使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合。
- 请求沿着链传递,直到有对象处理为止。
- 分为三个角色:
- Handler:抽象处理者,定义了一个处理请求的接口或者抽象类,通常会包含一个指向链中下一个处理者的引用。
- ConcreteHandler:具体处理者,实现抽象处理者的处理方法,如果能处理就处理,不能就转发给下一个。
- client:客户端,创建处理链,并向链的第一个处理者对象提交请求。
- 工作流程:
- 客户端将请求发送给链上的第一个处理者对象
- 接收到请求后是否能处理
- 可以就处理
- 不可以就转发给链上的下一个处理者
- 过程重复
- 场景:
- 过滤器链
- 日志记录
- 异常处理
- 认证授权
- 优缺点:
- 降低耦合度
- 实际举例:
- 比如在线商店,用户下单的时候需要
- 检查订单信息是否完整
- 检查商品库存是否充足
- 检查用户余额是否充足
- 确认订单,更新商品库存和用户余额
- 比如在线商店,用户下单的时候需要
public abstract OrderHandler{
procted OrderHandler next;
public void setNext(OrderHandler next){
this.next=next;
}
void handler(Order order);
}
public class CheckOrderHandler extends OrderHandler {
@Override
public void hand1e(Order order) {
//检查订单信息是否完整
if (order.isInfoComplete()) {
//如果订单信息完整,则将请求传递给下一个处理者
next.handle(order);
} else {
//如果订单信息不完整,则直接返回错误信息
throw new RuntimeException("订 单信息不完整");
}
}
public class CheckStockHandler implements OrderHandler {
public CheckStockHandler(OrderHandler next) {
this.next = next;
}
@Override
public void hand1e(Order order) {
//检查商品库存是否充足.
if (order.getStock() >= order.getQuantity()) {
//如果库存充足,则将请求传递给下一个处理者
next.handle(order);
} else {
//如果库存不足,则直接返回错误信息
throw new RuntimeException(" 商品库存不足");
}
}
}
public class CheckBalanceHandler implements OrderHandler {
public CheckBalanceHandler(OrderHandler next) {
this.next = next;
}
@Override
public void handle(Order order) {
//检查用户余额是否充足.
if (order.getBalance() >= order.getAmount()) {
//如果余额充足,则将请求传递给下一个处理者.
next.handle(order);
} else {
//如果余额不足,则直接返回错误信息
throw new RuntimeException("用户 余额不足");
}
}
}
public class ConfirmOrderHandler implements OrderHandler {
@Override
public void handle(Order order) {
//确认订单,更新商品库存和用户余额
order.confirm();
}
}
//客户端代码示例
CheckOrderHandler checkOrderHandler = new
CheckOrderHandler();
CheckStockHandler checkStockHandler = new CheckStockHand1er();
CheckBalanceHandler checkBalanceHandler = new CheckBalanceHandler();
ConfirmOrderHandler conf
irmOrderHandler =new
ConfirmOrderHand1er();
//将处理器按照一定顺序组成责任链
checkOrderHand1er.setNext(checkStockHandler);
checkStockHand1er.setNext(checkBalanceHandler);
checkBalanceHand1er.setNext(confirmOrderHandler);
// 处理订单
Order order = new Order();
checkOrderHandler.handle(order);
工厂模式?
- 创建型设计模式主要创建对现象,而不暴露对象的逻辑给客户端。
- 简单工厂
-
简单工厂模式的角色包括三个:
-
抽象产品 角色
-
public abstract class Weapon { /** * 所有的武器都有攻击行为 */ public abstract void attack(); }
-
具体产品角色
-
public class Tank extends Weapon{ @Override public void attack() { System.out.println("坦克开炮!"); } } /** * 战斗机(具体产品角色) * @version 1.0 * @className Fighter * @since 1.0 **/ public class Fighter extends Weapon{ @Override public void attack() { System.out.println("战斗机投下原子弹!"); } } /** * 匕首(具体产品角色) * @version 1.0 * @className Dagger * @since 1.0 **/ public class Dagger extends Weapon{ @Override public void attack() { System.out.println("砍他丫的!"); } }
-
工厂类 角色
-
public class WeaponFactory { /** * 根据不同的武器类型生产武器 * @param weaponType 武器类型 * @return 武器对象 */ public static Weapon get(String weaponType){ if (weaponType == null || weaponType.trim().length() == 0) { return null; } Weapon weapon = null; if ("TANK".equals(weaponType)) { weapon = new Tank(); } else if ("FIGHTER".equals(weaponType)) { weapon = new Fighter(); } else if ("DAGGER".equals(weaponType)) { weapon = new Dagger(); } else { throw new RuntimeException("不支持该武器!"); } return weapon; } }
优点:不需要关注对象创建细节,要什么对象直接向工厂要就可以,初步实现了生产和消费的分离。缺点:工厂为上帝类,不能出问题;不符合OCP开闭原则,扩展时需要修改工厂类。
-
spring通过依赖注入和面向接口编程解决
-
-
- 工厂方法
-
工厂方法模式既保留了简单工厂模式的优点,同时又解决了简单工厂模式的缺点。
工厂方法模式的角色包括:
-
抽象工厂角色
-
/** * 武器工厂接口(抽象工厂角色) * @author 动力节点 * @version 1.0 * @className WeaponFactory * @since 1.0 **/ public interface WeaponFactory { Weapon get(); }
-
具体工厂角色
-
/** * 具体工厂角色 * @author 动力节点 * @version 1.0 * @className GunFactory * @since 1.0 **/ public class GunFactory implements WeaponFactory{ @Override public Weapon get() { return new Gun(); } } package com.powernode.factory; /** * 具体工厂角色 * @author 动力节点 * @version 1.0 * @className FighterFactory * @since 1.0 **/ public class FighterFactory implements WeaponFactory{ @Override public Weapon get() { return new Fighter(); } }
-
抽象产品角色
-
/** * 武器类(抽象产品角色) * @author 动力节点 * @version 1.0 * @className Weapon * @since 1.0 **/ public abstract class Weapon { /** * 所有武器都有攻击行为 */ public abstract void attack(); }
-
具体产品角色
-
/** * 具体产品角色 * @author 动力节点 * @version 1.0 * @className Gun * @since 1.0 **/ public class Gun extends Weapon{ @Override public void attack() { System.out.println("开枪射击!"); } } package com.powernode.factory; /** * 具体产品角色 * @author 动力节点 * @version 1.0 * @className Fighter * @since 1.0 **/ public class Fighter extends Weapon{ @Override public void attack() { System.out.println("战斗机发射核弹!"); } }
扩展时增加一个产品+工厂,缺点:类爆炸
-
-
-
抽象工厂模式:
-
- 抽象工厂中包含4个角色:
-
抽象工厂角色
-
public abstract class AbstractFactory { public abstract Weapon getWeapon(String type); public abstract Fruit getFruit(String type); }
-
具体工厂角色
-
public class WeaponFactory extends AbstractFactory{ public Weapon getWeapon(String type){ if (type == null || type.trim().length() == 0) { return null; } if ("Gun".equals(type)) { return new Gun(); } else if ("Dagger".equals(type)) { return new Dagger(); } else { throw new RuntimeException("无法生产该武器"); } } @Override public Fruit getFruit(String type) { return null; } } public class FruitFactory extends AbstractFactory{ @Override public Weapon getWeapon(String type) { return null; } public Fruit getFruit(String type){ if (type == null || type.trim().length() == 0) { return null; } if ("Orange".equals(type)) { return new Orange(); } else if ("Apple".equals(type)) { return new Apple(); } else { throw new RuntimeException("我家果园不产这种水果"); } } }
-
抽象产品角色
-
具体产品角色
-
public abstract class Weapon { public abstract void attack(); } package com.powernode.product; public class Gun extends Weapon{ @Override public void attack() { System.out.println("开枪射击!"); } } public class Dagger extends Weapon{ @Override public void attack() { System.out.println("砍丫的!"); } }
优点:能保证一个工厂只使用一个类型的
-
缺点:不符合OCP、
-
-
- 抽象工厂中包含4个角色:
单例模式?
- 首先从单例模式关键点入手:
- 私有的构造方法
- 私有静态实例变量
- 共有静态方法
- 常见的单例模式:
- 饿汉式:final直接就保证了多线程的安全性了
public class Hungry {
static final Hungry hungry=new Hungry();
private Hungry(){
}
public static Hungry newInstance() {
return hungry;
}
}
- 懒汉式:
public class Lazy {
static Lazy lazy=null;
private Lazy(){
}
public static synchronized Lazy newInstance() {
if (lazy==null){
lazy=new Lazy();
}
return lazy;
}
//双重锁定检查,这里的对象要用volatile,意义在于避免每次都加锁
public static Lazy getInstance(){
if (lazy==null){
synchronized (Lazy.class){
if (lazy==null){
lazy=new Lazy();
}
}
}
return lazy;
}
}
两种,为了解决并发问题,一种是锁方法,第二种是双重锁定检查,双重的要加volatile
静态内部类:初始化的懒加载
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举单例,防止反射攻击,实例在类加载时就创建,线程安全,反序列化其他的是通过UNSAFE机制创建对象,解决了破坏单例的问题,最好的,枚举常量事实上就是类加载时初始化时创建的对象!!!
public enum Singleton {
SINGLETON(1);
int value;
Singleton(int value) {
this.value = value;
}
}
/**
* javap -c反编译
* public static com.单例模式.Singleton valueOf(java.lang.String);
* Code:
* 0: ldc #1 // class com/单例模式/Singleton
* 2: aload_0
* 3: invokestatic #16 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
* 6: checkcast #1 // class com/单例模式/Singleton
* 9: areturn
*
* static {};
* Code:
* 0: new #1 // class com/单例模式/Singleton
* 3: dup
* 4: ldc #30 // String SINGLETON
* 6: iconst_0
* 7: iconst_1
* 8: invokespecial #31 // Method "<init>":(Ljava/lang/String;II)V
* 11: putstatic #3 // Field SINGLETON:Lcom/单例模式/Singleton;
* 14: invokestatic #34 // Method $values:()[Lcom/单例模式/Singleton;
* 17: putstatic #7 // Field $VALUES:[Lcom/单例模式/Singleton;
* 20: return
* }
*/
单例模式带来的问题,和i++过程一样,需要三个步骤
分配内存空间给对象。
初始化对象。
将对象引用赋给引用变量。
但是因为指令重排,可能会变成
分配内存空间给对象。
将对象引用赋给引用变量。
初始化对象。
此时就出现了,后面进来的线程已经获得了引用,但是还没初始化,就会错误。所以要声明volatile
策略模式和模板设计模式?
- 策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法独立于使用它的客户而变化。
- 模板方法模式:
- 模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
-
public enum Singleton { SINGLETON(1) { @Override int doSome() { return value; } }; int value; Singleton(int value) { this.value = value; } public void doSomething() { System.out.println(doSome()); } abstract int doSome(); }
生产者消费者模式?
-
概念:生产者—消费者模式是一种常见的设计模式,用于在多线程环境中协调生产者和消费者之间的工作。它通过使用一个共享的缓冲区来实现生产者和消费者之间的解耦,使得生产者和消费者可以独立地执行,而不会相互阻塞。
-
java可以用LinkedBlockingQueue实现!!!
-
-
public static void main(String[] args) throws InterruptedException { BlockingQueue<String> queue = new LinkedBlockingQueue<>(); AtomicInteger integer = new AtomicInteger(1); Thread.ofVirtual().start(() -> { while (true) { queue.add(integer.getAndIncrement() + ""); try { Thread.sleep(200); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); Thread.sleep(100); Thread.ofVirtual().start(() -> { while (true) { try { System.out.println(queue.poll(1, TimeUnit.MINUTES)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); Thread.sleep(10000); }
观察者模式?
-
定义了对象间的一对多依赖关系,当一个对象的状态发生改变的时候,所有依赖与它的对象都会得到通知并且自动更新。
-
示例:ABCD四个线程,当A线程完成后BCD启动
-
抽象观察者:
public abstract class 抽象观察者 extends Thread { protected void doSomething() { this.start(); } }
- 具体观察者:
public class 具体观察者A extends 抽象观察者 { @Override public void run() { System.out.println("A观察者启动"); } }
- 抽象主题类:
abstract class 抽象主题类 extends Thread{ //维护观察者列表 private final Set<抽象观察者> observers = new HashSet<>(); // 注册观察者 public void attach(抽象观察者 observer) { observers.add(observer); } // 移除观察者 public void detach(抽象观察者 observer) { observers.remove(observer); } // 通知所有观察者 protected void notifyObservers() { for (抽象观察者 observer : observers) { observer.doSomething(); } } }
- 具体主题类:
public class 主题类 extends 抽象主题类{ @Override public void run() { // 模拟线程A的工作 System.out.println("线程A工作中..."); try { Thread.sleep(2000); // 模拟一些工作 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程A完成工作"); // 通知所有观察者 notifyObservers(); } }
代理模式?
-
代理类和目标类
-
静态代理
-
静态代理就是保留目标对象,去增强去调用
-
假设有一个目标对象OrderService
public class Client { public static void main(String[] args) { // 创建目标对象 OrderService target = new OrderServiceImpl(); // 创建代理对象 OrderService proxy = new OrderServiceProxy(target); // 调用代理对象的代理方法 proxy.generate(); proxy.modify(); proxy.detail(); } }
缺点是一个接口就要写一个代理类,导致类爆炸,速度快
-
- 动态代理
- JDK动态代理:这里可能会想,那岂不是所有方法都要执行invoke了,其实可以在invoke中加判断是否被这个注解修饰了
-
public static void main(String[] args) { // 第一步:创建目标对象 OrderService target = new OrderServiceImpl(); // 第二步:创建代理对象 OrderService orderServiceProxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), 调用处理器对象); // 第三步:调用代理对象的代理方法 orderServiceProxy.detail(); } public class TimerInvocationHandler implements InvocationHandler { // 目标对象 private Object target; // 通过构造方法来传目标对象 public TimerInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } }
- CGLIB动态代理:通过继承的方式
-
public static void main(String[] args) { // 创建字节码增强器 Enhancer enhancer = new Enhancer(); // 告诉cglib要继承哪个类 enhancer.setSuperclass(UserService.class); // 设置回调接口 enhancer.setCallback(方法拦截器对象); // 生成源码,编译class,加载到JVM,并创建代理对象 UserService userServiceProxy = (UserService)enhancer.create(); userServiceProxy.login(); userServiceProxy.logout(); } public class TimerMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // 前增强 long begin = System.currentTimeMillis(); // 调用目标 Object retValue = methodProxy.invokeSuper(target, objects); // 后增强 long end = System.currentTimeMillis(); System.out.println("耗时" + (end - begin) + "毫秒"); // 一定要返回 return retValue; } }
为什么有了JDK动态代理还要有CGLIB:无接口的类和更高的性能
-