生产者消费者模式:
生产者-消费者模式主要用于处理队列阻塞问题,实际生活中有许多类似的场景。例如,在面包生产流水线上,前后两个岗位之间存在密切的关联。生产面包的岗位可以视为生产者,而负责包装面包的岗位则是消费者。在这种情况下,生产者-消费者模式可以帮助协调生产和包装过程,确保生产和消费的平衡,从而优化整体生产效率,如图所示:
消费者需要等生产者生产出来才可以进行包装,如果生产者没有生产出来消费者就先进行等待,这就是典型的生产者消费者模式
这里附上生产者消费者代码:
public class ProducerConsumer {
public static void main(String[] args) {
PC pc = new PC();
Producer producer = new Producer(pc);
producer.setName("生产者");
Consumer consumer = new Consumer(pc);
consumer.setName("消费者");
producer.start();
consumer.start();
}
}
/**
* 提供生产和消费的操作
*/
class PC{
private int bread = 0;
/**
* 生产
*/
public synchronized void produceBread(){
if (bread < 10){
bread++;
System.out.println(Thread.currentThread().getName() + "生产到" + bread);
notify(); //启动消费者线程
}else{
try {
wait();//生产者等待
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
/**
* 消费
*/
public synchronized void consumeBread(){
if (bread > 0){
System.out.println(Thread.currentThread().getName() + "消费到" +bread);
bread--;
notify();//启动生产者线程
}else {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
/**
* 生产者类(Producer):继承Thread类,重写run()方法
*/
class Producer extends Thread{
private PC pc;
public Producer(PC pc){
this.pc = pc;
}
@Override
public void run() {
System.out.println(getName() + "开始生产......");
while(true){
try{
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
pc.produceBread();
}
}
}
/**
*消费者类(Consumer):继承Thread类,重写run()方法
*/
class Consumer extends Thread {
private PC pc;
public Consumer(PC pc){
this.pc = pc;
}
@Override
public void run() {
System.out.println(getName() + "开始消费........");
while(true){
try{
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
pc.consumeBread();
}
}
}
策略模式:
在日常生活中,策略模式的应用非常普遍。例如,当我们计划旅行时,可以选择乘坐飞机、高铁或火车等不同的交通工具。这种选择过程体现了策略模式的核心思想:根据不同的需求和条件选择最合适的策略。策略模式的代码示例如下:
public class Client {
public static void main(String[] args) {
Strategy strategyA = new ConcreteStrategyA();
Context context = new Context(strategyA);
context.algorithm();
}
}
class ConcreteStrategyA implements Strategy{
@Override
public void algorithm() {
System.out.println("执行策略A");
}
}
class ConcreteStrategyB implements Strategy{
@Override
public void algorithm() {
System.out.println("执行策略B");
}
}
class Context{
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
//调用策略类的算法
public void algorithm() {
strategy.algorithm();
}
}
strategy接口
public interface Strategy {
void algorithm();
}
模板方法模式:
假设我们在软件中需要处理不同类型的报告生成,报告的生成过程可能包括数据收集、数据处理和报告输出三个步骤。我们可以定义一个抽象的报告生成类,其中包含一个模板方法 generateReport()
来控制整个报告生成的流程。
- 抽象报告类:定义了
generateReport()
模板方法,其中包含了collectData()
、processData()
和printReport()
这几个步骤。 - 具体报告类:实现
collectData()
和processData()
方法,可以根据需要自定义数据收集和处理的逻辑。而printReport()
方法可以使用默认实现,也可以在子类中覆盖。
这种设计使得报告生成的流程可以得到控制和扩展,同时保持了代码的清晰和一致性。
简单描述:想象一下在饭堂打饭的流程:排队->打饭->付钱。这个过程是固定的,每个人都需要遵循。模板方法模式就像把这个固定的流程封装起来,让你只需要关注实际的业务——比如选择菜品、支付金额。模板方法模式负责控制流程的顺序,而具体的业务逻辑(例如你选择的菜或支付的方式)则留给子类去处理。这样做的好处是减少了重复代码,让你可以更专注于具体的实现细节。
abstract class AbstractClass {
// 模板方法
public final void templateMethod() {
step1();
step2();
step3();
}
// 抽象方法,子类需要实现
protected abstract void step1();
protected abstract void step2();
// 钩子方法,子类可以选择性地重写
protected void step3() {
// 默认实现
}
}
class ConcreteClass extends AbstractClass {
@Override
protected void step1() {
System.out.println("ConcreteClass step1");
}
@Override
protected void step2() {
System.out.println("ConcreteClass step2");
}
@Override
protected void step3() {
System.out.println("ConcreteClass step3");
}
}
public class Main {
public static void main(String[] args) {
AbstractClass obj = new ConcreteClass();
obj.templateMethod();
}
}
在Spring框架中的Jdbc Template就使用了模板方法
责任链模式:
假设我们在处理用户请求时,有不同的权限检查步骤:身份验证、权限验证、数据处理等。每个步骤可能需要对请求进行检查或处理。通过使用责任链模式,我们可以将这些步骤组织成一个链条:
- 身份验证处理者:检查用户的身份是否合法。如果合法,则将请求传递给下一个处理者。
- 权限验证处理者:检查用户是否有权限执行某个操作。如果有权限,则将请求传递给下一个处理者。
- 数据处理者:处理实际的业务逻辑,如数据库操作等。
如果某个处理者不能处理请求,它会将请求传递给链中的下一个处理者,直到请求被处理或者到达链的末端。这样,系统可以灵活地扩展新的处理步骤,而不需要修改现有的代码。
代码如下:
// 处理者接口
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(String request);
}
// 具体处理者A
class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(String request) {
if (request.equals("A")) {
System.out.println("Handler A processing request: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 具体处理者B
class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(String request) {
if (request.equals("B")) {
System.out.println("Handler B processing request: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNextHandler(handlerB);
handlerA.handleRequest("A"); // 处理请求 "A"
handlerA.handleRequest("B"); // 处理请求 "B"
handlerA.handleRequest("C"); // 没有处理者处理请求 "C"
}
}
在SpringMVC中就使用了责任链设计模式
-
前端控制器(DispatcherServlet):
- Spring MVC的前端控制器是
DispatcherServlet
,它充当整个请求处理链的入口点。所有的请求都会首先经过这个控制器。
- Spring MVC的前端控制器是
-
处理器映射器(HandlerMapping):
DispatcherServlet
根据请求的URL查找并确定相应的处理器(Controller)。这一过程由处理器映射器完成。处理器映射器决定哪个具体的处理器负责处理当前的请求。
-
处理器(Controller):
- 处理器是具体处理请求的组件。它接收到请求后,会执行相关的业务逻辑,并返回一个模型和视图(ModelAndView)。
-
视图解析器(ViewResolver):
- 视图解析器根据处理器返回的视图名称,找到相应的视图模板。视图解析器负责将模型数据渲染成最终的视图(如HTML页面)。
-
拦截器(Interceptor):
- 拦截器是处理链中的一个重要组成部分,它可以在请求到达处理器之前和处理器处理之后执行一些通用的操作(如日志记录、权限检查、事务管理等)。拦截器的执行顺序和位置可以通过配置来决定。
其实在实际开发中或多或少我们都用到了这些设计模式,就像平时我们使用spring和springMVC时就遇到了模板方法和责任链设计方法。