开发者

How to efficiently implement a strategy pattern with spring?

开发者 https://www.devze.com 2023-02-01 08:34 出处:网络
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 s

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.

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 :

<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 ?

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


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.

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

<?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


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 better to employ the Dependency Injection mechanism provided by the Spring framework - might as well put to use what your framework has to offer as one of its core strengths.


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(...);
        ...
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消