首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反射调用方法还是使用带有继承的固定方法?

反射调用方法还是使用带有继承的固定方法?
EN

Stack Overflow用户
提问于 2010-06-25 09:03:09
回答 3查看 1.8K关注 0票数 8

我正在开发一个小型的web库,我应该将HTTP处理程序方法称为GET、POST、PUT等反射与否。

固定方法

首先,带有if else ...块调用方法的变量在基类中给出,其中它们有一个默认实现,将一个错误返回给客户端。由于对不受支持的方法的请求需要一个包含允许方法的标头,所以我需要仔细查看哪些方法实际上是过度的(顺便说一下,就像Servlet所做的那样)。

代码语言:javascript
复制
public abstract class Resource {

    public Response handle(HttpServletRequest request) {
        String action = request.getMethod();
        if(action.equals("GET"))
            return get(request);
        else if(action.equals("POST"))
            return post(request);
        ...
    }

    protected Response get(HttpServletRequest request) {
        return new Response(METHOD_NOT_ALLOWED);
    }

    protected Response post(HttpServletRequest request) {
        return new Response(METHOD_NOT_ALLOWED);
    }

}

该解决方案的缺点是灵活性降低,因为在子类中重新实现handle方法之前,基类中的可用方法是固定的。

可变方法

另一个变体是根据其签名(接受HttpServletRequest并返回Response)反射地查找HTTP处理程序方法。这些方法将存储在map中,并根据映射中的键调用reflectivly。

代码语言:javascript
复制
public abstract class Resource {

    private Map<String, Method> handlers;

    public Resource() {
        handlers = findHttpHandlerMethodsReflectivly();
    }

    public Response handle(HttpServletRequest request) {
        String action = request.getMethod();
        Method handler = handlers.get(action);
        return (Response)handler.invoke(this, request);
    }

}

该解决方案的优点是实现简单、灵活,但是由于映射中的搜索和反射方法调用,缺点可能会增加一些运行时开销。类的接口有点“软”(或动态),编译器没有机会检查它。但我不确定这是否会是一个缺点,因为没有其他类应该依赖HTTP处理程序方法,它们是外部web接口和Java系统的边框。

战略模式

第三种选择和最干净的OOP将是“聚致洗脱剂”所建议的战略模式。看起来是这样的:

代码语言:javascript
复制
class MyResource extends Resource {

    register("GET", 
        new RequestHandler{
            @Override Response handle(HttpServletRequest request) {
                new Response(OK);
            }
        }
    );

}

它是干净的OOP,但代码实际上是丑陋和冗长的。我更喜欢在这里使用闭包的Scala,尽管对Scala的工具支持仍然很差。将其与继承和固定方法进行比较:

代码语言:javascript
复制
class MyResource extends Resource {

    @Override Response get(HttpServletRequest request) {
        return new Resonse(OK);
    }

}

你喜欢什么?为什么?其他想法?

解决方案

我已经了解到,由于HTTP方法的固定集合,这里不需要反射。策略模式的方法是干净的,但在我看来却是冗长的。因此,我决定使用固定方法和继承。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-06-25 09:08:54

如何使用接口而不是反射

在这种情况下,不应该使用反射,特别是因为不需要首先使用反射(参见有效的Java第2版,第53项:更喜欢接口而不是反射)。

您应该定义一个java.lang.reflect.Method类型,而不是使用Map<String, Method> handlers,而应该使用一个Map<String, RequestHandler> handlers类型。

看起来会是这样的:

代码语言:javascript
复制
interface RequestHandler {
   Response handle(HttpServletRequest req);
}

然后,不要反思广益地搜索处理程序,而是使用显式put填充映射(或者使用配置文件等)。然后,您可以更清晰地调用Method.invoke,而不是反射式的RequestHandler.handle

关于enum键选项

如果您只有几种不同类型的请求方法而没有使其可扩展的计划,则可以使用enum RequestMethod { GET, POST; }

这允许您声明一个Map<RequestMethod, RequestHandler> handlers;。请记住,enum有一个valueOf(String)方法,您可以使用该方法从名称中获取常量。

interfaceabstract class的使用

在这里,我将再次遵从有效Java 2的乔希·布洛赫的判断,第18项:更喜欢接口而不是抽象类

总结说,interface通常是定义允许多个实现的类型的最佳方法。这条规则的一个例外是,进化的易用性被认为比灵活性和力量更重要。在这种情况下,您应该使用abstract class来定义类型,但前提是您理解并能够接受这些限制。

这本书更详细地介绍了你正在努力解决的问题。在这种特殊情况下,可能会出现使用abstract class (即“固定方法”方法)的情况,因为有少数几种固定类型的请求方法。

票数 9
EN

Stack Overflow用户

发布于 2010-06-25 09:08:22

我不喜欢在这里使用反射,因为可能的HTTP方法是众所周知的,而且不会在短期内改变。因此,由于额外的复杂性和缺乏运行时检查,您并没有真正获得任何东西。但是,您可以使用一个映射来代替if...elseif,以使您的代码更简洁、更易于扩展。

目前,如果使用"NOSUCHMETHOD“之类的方法名调用反射代码,则会崩溃。

票数 7
EN

Stack Overflow用户

发布于 2010-06-25 11:44:26

一个好的OO设计应该支持可扩展性,但当它是必要的时候。这里有一些关于扩展性意味着什么(对我来说)的一些想法,我和你们分享。

第一级:无扩展性

每件事都是事先知道的,你可以用最简单和最容易理解的方式对它进行编码。

第2级:用钩子封装扩展性

组件封装得很好,但必须能够调整其行为或配置它。然后,组件提供了一个钩子,您可以在其中插入一些东西来改变它的行为。这个钩子可以有很多不同的形式。例如,如果组件提供了一种将策略挂钩到它的方法,或者如果组件内部使用了带有<verb, actionHandler>的映射,但是映射是由另一个组件在外部填充的,等等。

第3级:运行时扩展性

在高级情况下,代码是动态加载的,系统是用DSL表示的自定义规则的“脚本”,等等,这种灵活性要求使用反射,因为需要以动态的方式调用代码。

在您的示例中,HTTP谓词列表是固定的,并且是资源内部的。然后我会选择最简单的方法,使用方法1。在我看来,其他的东西看起来都过于工程化了,当它被证明是合理的时候,我不介意列出一个if-else列表。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3116781

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档