Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 重构庞大类时如何使用spring_Java_Spring_Class Design - Fatal编程技术网

Java 重构庞大类时如何使用spring

Java 重构庞大类时如何使用spring,java,spring,class-design,Java,Spring,Class Design,这是一个关于java类设计以及它如何与spring交互的一般性问题,但我将尝试使用一个示例来简化讨论。(请注意,此代码主要是psedo代码,排除了大量的绒毛) 想象一下,我们遇到了一个大的类,它的系数很低。它做了很多事情,使得重用、测试或理解变得更加困难。在我的示例中,我们有一个“BulkyThingDoer”类,它既可以做一件事,也可以跟踪一件事做了多少次以及需要多长时间(发布到JMX)的统计信息。这并不可怕,但随着统计数据数量的增加,课堂上的记录工作变得占主导地位,而课堂上真正重要的事情却消

这是一个关于java类设计以及它如何与spring交互的一般性问题,但我将尝试使用一个示例来简化讨论。(请注意,此代码主要是psedo代码,排除了大量的绒毛)

想象一下,我们遇到了一个大的类,它的系数很低。它做了很多事情,使得重用、测试或理解变得更加困难。在我的示例中,我们有一个“BulkyThingDoer”类,它既可以做一件事,也可以跟踪一件事做了多少次以及需要多长时间(发布到JMX)的统计信息。这并不可怕,但随着统计数据数量的增加,课堂上的记录工作变得占主导地位,而课堂上真正重要的事情却消失在噪音中。如果我们有一个相互竞争的DoerInterface实现,我们将需要复制相同的统计工具等

@Component
@ManagedResource
public class BulkyThingDoer implements DoerInterface, DoerStatistics{
  private int thingsDone = 0;
  private long timeSpentDoingThings = 0;

  public void doThing(){
    long start = System.currentTimeMillis();
    // do the important thing
    thingsDone ++;
    timeSpentDoingThings += System.currentTimeMillis() - start;
  }
  public int getThingsDone(){ return thingsDone;}
  public long getTimeSpentDoingThings (){ return timeSpentDoingThings;}
}
现在让我们想象一下,我们重构这个类,将所有的统计簿记拆分成一个helper对象,然后让实际的行为人报告(尽可能高的级别)发生了什么。现在ThingDoer和DoersStatistics对象都是简单的、可测试的、单一责任对象

@Component
public class ThingDoer implements DoerInterface {
  private final DoerStatistics stats;

  public ThingDoer(DoerStatistics stats){
    this.stats = stats;
  }

  public void doThing(){
    long start = System.currentTimeMillis() - start;
    // do the important thing
    stats.recordThatWeDidThing(System.currentTimeMillis() - start);
  }
}

@ManagedResource
public class DoerStatisticHolder implements DoerStatistics{
  private int thingsDone = 0;
  private long timeSpentDoingThings = 0;

  public void recordThatWeDidThing(long duration){
    thingsDone ++;
    timeSpentDoingThings += duration;
  }
  public int getThingsDone(){ return thingsDone;}
  public long getTimeSpentDoingThings (){ return timeSpentDoingThings;}
}
对我来说,这显然是一个很好的重构开始,我认为这是扩展DI原则,一直到实现的细节

这就是这个问题的导火索:一旦我完成了重构,我的类就很难在spring上下文文件中使用了。在此之前,我可以只使用一个定义,将同一个对象创建为一个bean,我可以给其他对象(或autowire),现在我必须在上下文中定义多个部分,并手动将它们连接在一起。这将向用户公开比必要的更多的实现细节

一种替代方法是,然后有效地重建“BulkyThingDoer”助手类,以使用正确的片段构造我的对象:

public class DelegatedBulkyThingDoer extends DoerInterface{
  ThingDoer doer;

  public DelegatedBulkyThingDoer(){
    DoerStatistics stats = new DoerStatisticHolder();
    doer= new ThingDoer(stats );
  }

  public void doThing(){
    doer.doThing();
  }
}
这解决了一些可用性问题,但现在我没有在DoerStatisticHolder或ThingDoer上获得任何spring魔力。在本例中,这意味着从未注册过JMX。若有一种简单的方法来通知spring正在创建这些子对象,那个么很可能会解决我的问题

当然,我可以委托我们在最初的笨重实现中进行的所有调用,并删除两个实现类中的所有注释,但这听起来非常不雅观。我会再次有效地重建BulyClass,这尤其令人恼火,因为它只对JMX或日志记录等横切关注点有必要

我认为,正是这种痛苦导致最初的实现变得如此庞大和复杂。Spring似乎诱导开发人员停止在实现级别应用严格的OOP原则,因为这样的困难。在我深入研究的springified代码库中,这种模式反复出现,这些类最终在一个类中实现,以支持“高级”spring上下文使用(单bean def),而不会进一步崩溃,因为在这种情况下,我们失去了spring的魔力


我和Spring和Javajava(过去几年中一直在C++、Scala和Ruby)比较新,所以我可能缺少一些东西。java/spring开发人员如何处理spring可用性和良好实现之间的“阻抗不匹配”?他们是不是咬紧牙关,创造了一个大批量的授权,强制用户构造我的重构impl类,或者只使用BulkyClass模式,因为这是最简单的?

像BulkyThingDoer一样,您可以使用
@组件对DoerStatisticHolder进行注释,这样它将由spring管理,然后您可以使用
@autowire
将其自动连接到ThingDoer中。一个缺点是您还需要一个非参数构造函数

如果您总是需要一个对象的新实例,您可以使用
@Scope(“prototype”)
对其进行附加注释


对于只有一个实际实现的自动连接类,使用基于注释的配置方法可以节省大量的xml配置开销。

为什么不编写一个通用的
DoerStatisticBean
,作为任何类的代理呢。将实际bean包装到代理中,例如使用
BeanFactoryPostProcessor
并使用Spring将代理发布到JMX。或者使用面向方面的编程,例如AspectJ或Spring AOP来解决您的跨领域问题。编码——这并不是不合理的,但它确实说明了我的观点:在春季,使用功能良好的片段实现您的代码是在与潮流作斗争。我不认为这是Spring的问题。这是一个普遍的问题,因为一个普通的java应用程序还需要创建两个类的实例来使用它们,或者使用一个在内部创建这些实例的工厂方法。因此,首先您应该考虑没有spring的客户机如何使用您的类,但是如果您总是希望spring就位,那么您可以实现一个定制的
NamespaceHandler
,它为您的复杂bean提供一个简单的XML配置,与aop命名空间相当。(要更正我的评论,它必须是
BeanPostProcessor
而不是
BeanPactoryPostProcessor
)。这是一个一般性问题,不适合任何直接回答。这教会了我一些关于sprint的有用的东西,所以我接受它。谢谢