如何使用Java之类的OOP语言封装帮助程序函数(常用api)? [英] How to encapsulate the helper functions(commonly used apis) in a OOP language like java?

查看:82
本文介绍了如何使用Java之类的OOP语言封装帮助程序函数(常用api)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这些功能可能很难放入特定的类中,

These functions may be hard to fit into a specific class,

与他们打交道的最佳做法是什么?

what's the best practice to deal with them?

推荐答案

我想你是说方法而不是函数?您应该真正想象一下static这个词在Java世界中不存在,从长远来看,static实际上不会为您带来任何好处.

I suppose you mean methods instead of functions? You should really imagine the word static doesn't exist in Java world, there really isn't a case where static would actually do you anything good in the long run.

我目前实际上正面临着类似的问题,我想提供一堆API方法供用户使用,但是我想在下面隐藏实际方法以隐藏实现细节.

I'm actually currently facing a similar problem, I have a whole bunch of API methods I want to give out for users to meddle with but I want to hide the actual methods underneath to hide the implementation details.

当然,问题是,如果我只是将所有内容都塞进一类,那么即使有可用的最佳自动完成工具,它也会变得笨拙且难以使用.您最可能遇到的问题实际上与这些方法的放置位置无关,而是如何向用户展示这些方法.

The problem of course is that if I just cram everything into one class, it becomes humongous and hard to use even with the best autocompletion tools available. The problem you have most likely really isn't about where to put those methods but how to present them to the user.

要解决这个问题,建议您创建一个对象层次结构,在其中通过调用myUtil.someGroup().someMethod(param1, param2);来访问您的帮助器方法.这实际上是某些API:s已经起作用的方式,例如流行的Web框架

To solve that I'd suggest you create a hierarchy of objects where you access your helper methods by calling myUtil.someGroup().someMethod(param1, param2); This is actually how some API:s already work, for example popular Web framework Apache Wicket is configured by using Settings object which uses composition to allow itself to have multiple groups of distinct features.

要真正将其从理论上充实为一个实际的示例,请假设您有许多图像处理方法,这些方法可以转换图像的尺寸或更改其属性(如颜色,亮度和对比度).而不是拥有这个

To really flesh out this from theory to a working example, lets assume you have a bunch of image manipulation methods which either transform the image's dimensions or change its properties like color, brightness and contrast. Instead of having this

public class ImageUtil {

    public static BufferedImage adjustHue(float difference,
                                          BufferedImage original) {
        /* ... */
        return adjusted;
    }

    public static BufferedImage adjustBrightness(float difference,
                                                 BufferedImage original) {
        /* ... */
        return adjusted;
    }

    public static BufferedImage adjustContrast(float difference,
                                               BufferedImage original) {
        /* ... */
        return adjusted;
    }

    public static BufferedImage setHeight(int newHeight,
                                          BufferedImage original) {
        /* ... */
        return adjusted;
    }

    public static BufferedImage setWidth(int newWidth,
                                         BufferedImage original) {
        /* ... */
        return adjusted;
    }

}

您应该使用这些界面来描述每组操作

you should instead have these interfaces to describe each set of operations

public interface IImageColorOperations {

    BufferedImage adjustHue(float difference, BufferedImage original);

    BufferedImage adjustBrightness(float difference, BufferedImage original;)

    BufferedImage adjustContrast(float difference, BufferedImage original);

}

public interface IImageDimensionOperations {

    BufferedImage setHeight(int newHeight, BufferedImage original);

    BufferedImage setWidth(int newWidth, BufferedImage original);

}

,以及在主"图像实用程序类中实例化的每个接口的相应单独类,

and an accompanying separate class for each interface which you instantiate in your "main" image utility class like so

public class ImageUtils {

    private final IImageDimensionOperations dimension;
    private final IImageColorOperations color;

    public ImageUtils() {
        this(new ImageDimensionOperations(),
             new ImageColorOperations());
    }

    /**
     * Parameterized constructor which supports dependency injection, very handy
     * way to ensure that class always has the required accompanying classes and
     * this is easy to mock too for unit tests.
     */
    public ImageUtils(IImageDimensionOperations dimension,
                      IImageColorOperations color) {
        this.dimension = dimension;
        this.color = color;
    }

    /* utility methods go here */

}

但是等等,这还不是全部!现在有两条路要走,您可以自己决定要选择哪一条.

But wait, this isn't all! There's now two paths to go, you can decide for yourself which one you'd like to take.

首先,您可以使用组合直接显示接口方法:

First, you can use composition to expose the interface methods directly:

public class ImageUtils implements IImageDimensionOperations,
                                   IImageColorOperations {

    private final IImageDimensionOperations dimension;
    private final IImageColorOperations color;

    public ImageUtils() {
        this(new ImageDimensionOperations(),
             new ImageColorOperations());
    }
    /* etc. */
}

有了这个,您只需要将对各种方法的调用委派给实际的操作类即可.缺点是,如果添加其他方法,则必须同时修改此实用工具类和基础实现类.

With this, you just need to delegate the the calls to various methods to the actual operation class. Downside to this is that if you add another method, you have to modify both this utility class and the underlying implementation class.

您的第二选择是直接公开操作类本身(这就是为什么我在其中添加这些finals的原因!):

Your second choice is to expose the operation classes themselves directly (that's why I added those finals there!):

public class ImageUtils {

    public final IImageDimensionOperations dimension;
    public final IImageColorOperations color;

    public ImageUtils() {
        this(new ImageDimensionOperations(),
             new ImageColorOperations());
    }    

    public ImageUtils(IImageDimensionOperations dimension,
              IImageColorOperations color) {
        this.dimension = dimension;
        this.color = color;
    }

    /* Nothing else needed in this class, ever! */

}

通过执行此操作,您会得到那些漂亮的呼叫,例如

by doing this you get those nice looking calls such as

BufferedImage adjusted = imageUtils.color.adjustHue(3.2f, original);

,并且当您向任一接口添加某种方法时,它们已经在图像实用程序类中可用,而无需进行任何其他修改.是的,一般而言,公共字段在Java中是大忌,但我确实认为在这种情况下这并不是一件坏事,尤其是finals将字段标记为不可修改(至少在理论上).

and when you add some method to either of the interfaces, you already have them available in your image utility class without any additional modification. Yes, generally public fields are a big no-no in Java, however I do think that in this case that's not such a bad thing, especially with the finals marking the fields as unmodifiable (at least in theory).

这篇关于如何使用Java之类的OOP语言封装帮助程序函数(常用api)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆