如何应对可怕的Struts Actions?

发布于 2024-07-07 01:43:16 字数 298 浏览 8 评论 0原文

我使用 Struts 1.2.4 继承了这个巨大的遗留 Java Web 应用程序。 我有一个关于行动的具体问题。 大多数页面只有一个 Action,并且 processExecute() 方法是可怕的怪物(非常长且基于请求参数的大量嵌套 if 语句)。

鉴于操作是命令模式的一种实现,我正在考虑将这些操作拆分为每个用户手势一个操作。 但这将是一次大规模的重构,我想知道:

  1. 这是正确的方向吗?
  2. 我是否可以采取中间步骤,一种处理整体操作内部混乱的模式? 也许动作中还有另一个命令模式?

I inherited this gigantic legacy Java web app using Struts 1.2.4. I have a specific question regarding Actions. Most of the pages have exactly one Action, and the processExecute() methods are hideous monsters (very long and tons of nested if statements based on request parameters).

Given that Actions are an implementation of the command pattern, I'm thinking to split these Actions into one Action per user gesture. This will be a large refactoring though, and I'm wondering:

  1. Is this the right direction?
  2. Is there an intermediate step I could take, a pattern that deals with the mess inside the monolithic actions? Maybe another command pattern inside the Action?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

黄昏下泛黄的笔记 2024-07-14 01:43:16

我处理这个问题的方法是:

  • 每当你改变任何东西时,不要“立即做所有事情”
  • ,让它比你发现它时更好
    • 用单独的 Action 实现替换条件是其中一个步骤。
    • 更好的是:将您的实现与 Action 类分开,以便在更改框架时可以使用它
    • 保持新的 Command 实现绝对不引用 Struts,使用新的 Actions 作为这些实现的包装器。
    • 您可能需要为 Struts ActionForm 提供接口,以便在不复制所有数据的情况下传递它们。 另一方面 - 您可能想要传递除 ActionForms 之外的其他对象,这些对象通常是一堆字符串(请参阅有关 Struts 1.2 ActionForm)
  • 开始将部件迁移到较新的版本 更好的技术。 Struts 1.2 刚推出时非常棒,但绝对不是您想要永远支持的。 现在有几代更好的框架。

肯定还有更多 - 抱歉,我的时间不多了......

My way of dealing with this would be:

  • dont do 'everything at once'
  • whenever you change anything, leave it better than you found it
    • replacing conditionals with separate Action implementations is one step.
    • Better yet: Make your implementations separate from the Action classes so that you can use it when you change frameworks
    • Keep your new Command implementation absolutely without references to Struts, use your new Actions as Wrapper around these implementations.
    • You might need to provide interfaces to your Struts ActionForms in order to pass them around without copying all the data. On the other hand - you might want to pass around other objects than ActionForms that are usually a bunch of Strings (see your other question about Struts 1.2 ActionForms)
  • start migrating parts to newer & better technology. Struts 1.2 was great when it came out, but is definitely not what you want to support in eternity. There are some generations of better frameworks now.

There's definitely more - Sorry, I'm running out of time here...

作妖 2024-07-14 01:43:16

在我看来,Struts Actions 中根本不应该包含太多代码。 他们应该直接与请求和响应交互 - 从表单或请求参数中获取一些数据,将该信息传递给服务层,然后将一些内容放入 Response 对象中,或者可能在用户会话中保存一些数据。

我建议不要使用操作类进行继承。 一开始这听起来是个好主意,但我认为迟早你会意识到你是在硬塞东西,而不是真正使代码库变得健壮。 Struts 有足够的基本操作,如果您要创建新的操作,您可能在 Web 层中获得了不应该存在的代码。

这只是我的个人经历。

Struts Actions, in my mind, shouldn't have very much code in them at all. They should just interact directly with the request and response - take some data from a form or a request parameter, hand that info off to the Service Layer, and then put some stuff in a Response object or maybe save some data in the user's session.

I'd recommend staying away from doing inheritance with action classes. It sounds like a good idea at first but I think sooner or later you realize that you're shoe-horning things more than you're actually making the code base robust. Struts has enough base actions as is, if you're creating new ones you've probably got code in the web layer that shouldn't be there.

That is just my personal experience.

世界如花海般美丽 2024-07-14 01:43:16

我以前处理过这类事情。 好的第一步是将另一个基类插入到 Action 和一个原始的巨大操作类(我们称之为 ClassA)之间的继承链中。 特别是如果您没有时间一次完成所有事情的话。 然后,您可以开始将功能片段提取到更小的并行操作类(ClassB、ClassC)中。 原始 ClassA 和新重构类之间的任何共同点都可以提取到新的基类中。 所以层次结构现在看起来像这样:

Original Hierarchy:      New Hierarchy:

     Action                   Action
       |                        |
       |                      BaseA
  (old)ClassA                   |
                       +--------+----------+
                       |        |          |
                   ClassB (new)ClassA   ClassC

I've dealt with this type of thing before. A good first step is to insert another base class into the inheritance chain between Action and one of the original monstrous action classes (lets call it ClassA). Especially if you don't have time to do everything at once. Then you can start pulling out pieces of functionality into smaller parallel Action classes (ClassB, ClassC). Anything that's common between the original ClassA and the new refactored classes can be pulled up into the new base class. So the hierarchy now looks like this:

Original Hierarchy:      New Hierarchy:

     Action                   Action
       |                        |
       |                      BaseA
  (old)ClassA                   |
                       +--------+----------+
                       |        |          |
                   ClassB (new)ClassA   ClassC
时光倒影 2024-07-14 01:43:16
  1. 一次只使用一种方法
  2. 记录一些测试用例,以便稍后回放。 示例(确保在代码中找到尽可能多的路径,即页面上调用此操作的所有用户手势)
  3. 重构该方法,通过创建执行较小操作的较小方法来降低其复杂性。
  4. 执行此操作时重新运行测试

此时,您已经重构了令人讨厌的巨大方法的版本。 现在您实际上可以开始创建特定操作。

您可以使用新重构的类作为基类,并使用这些重构的小方法将每个特定操作作为子类实现。

完成此操作后,您应该对类之间共享的逻辑有一个很好的了解,并且可以根据需要上拉或下推这些方法。

这并不有趣,但如果您将在代码库上工作一段时间,它将节省您的时间和麻烦。

  1. Go one method at a time
  2. Record some test cases you can play back later. Example here (make sure to hit as many paths through the code as you can, i.e. all user gestures on the page that call this action)
  3. refactor the method to reduce its complexity by creating smaller methods that do smaller things.
  4. Re-run tests as you do this

At this point, you have refactored version of the big huge annoying method. Now you can actually start creating specific actions.

You can use your newly refactored class as a base class, and implement each specific action as a subclass using those refactored small methods.

Once you've done this, you should have a good picture of the logic shared between the classes and can pull-up or push-down those methods as needed.

It's not fun, but if you will be working on the codebase for a while, it will save you time and headaches.

梦罢 2024-07-14 01:43:16

这是一个棘手的问题,但却是早期 Web 应用程序开发的典型问题。

首先你需要开始思考哪些逻辑构成了业务行为,哪些逻辑构成了“流”(即用户看到的内容),以及哪些逻辑获取了他所看到的内容。

您不必沿着工厂和接口之类的路线走下去; 追溯实现的用处要小得多...但是将业务逻辑和数据检索逻辑合并到某种委托中...并让 struts 操作根据该逻辑的成功/失败来确定页面流。

从那里你只需要花几周的时间来磨练它

Tough problem but typical of early web app development.

First things first you need to start thinking about which logic constitutes business behavior, which logic constitutes "flow" (i.e. what the user sees), and which logic gets the content for what he sees.

You don't have to go down the route of factories and interfaces and all that; retroactive implementation is far less useful... but consolidating business logic and data retrieval logic into delegates of some kind... and leaving the struts actions to determine page flow based on success/failure of that logic.

From there you just have to take a few weeks and grind it out

你怎么敢 2024-07-14 01:43:16

一个长方法永远都不好,除非它碰巧是单个 switch 语句,其中 case 非常短(令牌解析或类似的东西)。

您至少可以将长方法重构为具有描述性名称的较小方法。

如果可能的话,您可以通过检查表单来识别它应该做什么来开始您的方法,然后使用 if/else 找到各种选项。 虽然没有嵌套的 if,但这些往往会使代码不可读。 只要

enum Operation {
  ADD, DELETE;
}

...

Operation operation = determineOperation(form);
if (operation == Operation.DELETE) { 
  doDelete(form); 
} else if (operation == Operation.ADD) {
  doAdd(form);
}

你能做到这一点,你的逻辑就干净整洁,你就可以做任何你想做的重构。

困难的部分是让你的逻辑清晰,你可以分步骤做到这一点。 在您确切了解问题所在之前,不要选择模式。

One long method is never good, unless it happens to be a single switch statement where the cases are very short (token parsing or something like that).

You could at least refactor the long method into smaller methods with descriptive names.

If at all possible you could start your method with recognizing what it is it should do by examining the form, and then if/else your way to the various options. No nested ifs though, those tend to make code unreadable. Just

enum Operation {
  ADD, DELETE;
}

...

Operation operation = determineOperation(form);
if (operation == Operation.DELETE) { 
  doDelete(form); 
} else if (operation == Operation.ADD) {
  doAdd(form);
}

If you can go that far you have your logic nice and clean and you can do whatever refactoring you want.

The hard part is to get your logic clear, and you can do that in steps. Don't choose a pattern untill you understand exactly what your problem is.

爱本泡沫多脆弱 2024-07-14 01:43:16

如果您计划重构代码,您应该确保首先为现有代码编写测试,这样您就可以确保在开始重构后没有更改它的功能。

If you're planning to refactor the code you should make sure to write tests for the existing code first so you can be sure you haven't altered the functionality of it once you start refactoring.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文