java 如何使用 spring 有效地实施策略模式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4553377/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 06:55:46  来源:igfitidea点击:

How to efficiently implement a strategy pattern with spring?

javaspringdependency-injectionstrategy-pattern

提问by Anth0

I have a web application developped in Java 1.5 with Spring framework. Application contains "dashboards" which are simple pages where a bunch of information are regrouped and where user can modify some status. Managers want me to add a logging system in database for three of theses dashboards. Each dashboard has different information but the log should be traced by date and user's login.

我有一个使用 Spring 框架在 Java 1.5 中开发的 Web 应用程序。应用程序包含“仪表板”,它们是简单的页面,在其中重新组合了大量信息,并且用户可以在其中修改某些状态。经理希望我在数据库中为三个仪表板添加日志系统。每个仪表板都有不同的信息,但日志应按日期和用户登录进行跟踪。

What I'd like to do is to implement the Strategy pattern kind of like this :

我想要做的是实现这样的策略模式:

interface DashboardLog {
   void createLog(String login, Date now);
}

// Implementation for one dashboard
class PrintDashboardLog implements DashboardLog {
  Integer docId;
  String status;

  void createLog(String login, Date now){
    // Some code
  }
}

class DashboardsManager {
  DashboardLog logger;
  String login;
  Date now;

  void createLog(){
     logger.log(login,now);
  }
}

class UpdateDocAction{
   DashboardsManager dbManager;

   void updateSomeField(){
      // Some action
      // Now it's time to log
      dbManagers.setLogger = new PrintDashboardLog(docId, status);
      dbManagers.createLog();
   } 
}

Appcontext.xml :

应用上下文.xml :

<bean id="dashboardManagers" class="...DashboardManagers" />

In this solution I'm therefore not using dependency injection. Is it "correct" (good practice, performance, ...) to do it this way ? Is there a better way where I could use DI ?

因此,在这个解决方案中,我没有使用依赖注入。这样做是否“正确”(良好的实践,性能,...)?有没有更好的方法可以使用 DI ?

Note :I did not write basic stuff like constructors and getter/setter.

注意:我没有写基本的东西,比如构造函数和 getter/setter。

采纳答案by anirvan

While it is perfectly "correct" to employ the strategy pattern as you have, but considering the fact that you're using Spring - it would be betterto employ the Dependency Injectionmechanism provided by the Spring framework - might as well put to use what your framework has to offer as one of its core strengths.

虽然使用您所拥有的策略模式是完全“正确的”,但考虑到您正在使用 Spring 的事实 -最好使用Spring 框架提供的依赖注入机制 - 不妨使用什么您的框架必须作为其核心优势之一提供。

回答by Adriaan Koster

Your solution will create a new instance of PrintDashboardLog for each call to updateSomeField(). This might take up unnecessary time/memory/GC-effort. Also, from a design perspective it makes sense if there is one DashboardLog for each Dashboard, not a new one for each call.

您的解决方案将为每次调用 updateSomeField() 创建一个新的 PrintDashboardLog 实例。这可能会占用不必要的时间/内存/GC 工作量。此外,从设计的角度来看,如果每个 Dashboard 有一个 DashboardLog,而不是每次调用都有一个新的 DashboardLog,这是有道理的。

I think it may be a good idea to use aspects for which Logging is one of the exemplary usecases. Something like:

我认为使用 Logging 是示例用例之一的方面可能是个好主意。就像是:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <bean id="loggingAspect" class="com.yourcompany.yourapplication.aspects.DashboardLogAspect" />

    <aop:aspectj-autoproxy>
        <aop:include name="loggingAspect" />
    </aop:aspectj-autoproxy>

</beans>    


package com.yourcompany.yourapplication.aspects;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class DashboardLogAspect {

    @Around("execution(* com.yourcompany.yourapplication..*Action+.*(..)) && target(target)")
    public Object logActionCall(ProceedingJoinPoint pjp, Object target) throws Throwable {

        long before = System.nanoTime();

        Object returnValue = pjp.proceed();

        long after = System.nanoTime();
        long durationNs = after - before;

        String logMsg = target.getClass() + "." + pjp.getSignature().toShortString() + " (" + durationNs + " ns)";

        // TODO: store the log message in your database
        System.out.println(logMsg);

        return returnValue;
    }            
}

This logs all calls to application classes with a name ending in 'Action'. It also adds the time each call took to complete. You might want to tweak the Around advice for a specific method name pattern as well. See the AspectJ programming guide

这会记录对名称以“Action”结尾的应用程序类的所有调用。它还增加了每个调用完成的时间。您可能还想针对特定的方法名称模式调整 around 建议。请参阅AspectJ 编程指南

回答by DwB

If each "dashboard" is has a controller, why not call the logging from the controller.

如果每个“仪表板”都有一个控制器,为什么不从控制器调用日志记录。


public interface DashboardLog
{
    void createLog(...);
}

public class DashboardUno
implements DashboardLog
{
    ...
    public void createLog(...)
    { ... }
}

@Controller
@RequestMapping("/blah/schmarr")
public class BlahController
{
    ...
    @RequestMapping(value = "/xxx")
    public String someMeaningfulName(...)
    {
        DashboardUno elEsUno;
        ... get the dashboard object ...
        elEsUno.createLog(...);
        ...
    }
}