具有小变化的重复结构的Java方法构造

时间:2017-11-10 18:44:04

标签: java design-patterns

我不确定是否有一个涵盖这个问题的模式,但是这里有。在编写调用分析算法(例如解析器或计算实现)的方法时,有相当多的代码来读取源,应用算法,然后将结果转换为有用的东西。基本上是20-30行代码和一个经常变化的算法/解析器/标记器。

所以....到目前为止我看到的选项是:

  1. 为每个算法创建一个新方法(由于重复而丑陋)
  2. 创建一个方法并将算法作为参数传递,然后使用case或if / then来选择算法(这会变得混乱,因为我必须硬编码我的算法选择。
  3. 创建一个单独的初始化或算法设置,然后检查它是否在方法中初始化(这仍然是丑陋的,因为在其他地方,我的选择方法中有不同算法选择的硬编码列表)。 / LI>

    是否有一个巧妙的技巧或一般方法构造编程模式来解决这个问题?

    提前致谢。

    - 编辑 -

    要删除这个问题的一些抽象,这里是我所谈论的原型。所以真的只有tokenizer的实现发生了变化。

    pubic void tokenizeData(Filename datablob){
        // convert filename
        // open file
        // handle file errors
        // other code
    
        // assign desired tokenizer
        tokenizer = new TokenizerImplementation (or some other variation);
    
        tokenizedData = tokenizer( cleansedData );
    
        // parsing and collection code
        // more error processing code
        // cleanup code
    }
    

2 个答案:

答案 0 :(得分:1)

我还会根据@Lucas Oliveira的建议,对InterfaceAbstract + Template Method的某些组合进行个人访问,但是对于选择适当的Tokenizer实现的问题,您可能还需要 Factory (模式)来动态加载另一个Tokenizer impl。基于工厂上下文或参数而不更改模板方法tokenizeData()的内容。

示例1经典参数化工厂:

public class TokenizerFactory 
{
    private static final Logger logger = LoggerFactory.getLogger(TokenizerFactory.class);

    private final int version;

    public TokenizerFactory(int version) { 
        this.version = version; 
    }

    public ITokenizer getInstance() {
        switch(version) {
            case 1: return new TokenizerV1();
            case 2: return new TokenizerV2();
            default: return new DefaultTokenizer();
        }
    }
}

示例2动态类加载静态工厂(原谅我的名字):

public class TokenizerFactory 
{
    private static final Logger logger = LoggerFactory.getLogger(TokenizerFactory.class);

    private TokenizerFactory() {}

    // Here eg. ETokenizerType is a enum storing class associated to the type.
    public static ITokenizer getInstance(ETokenizerType dtype) {
        try {
            return (ITokenizer)dtype.getClassVar().newInstance();
        }
        catch(Throwable ex)  {
            logger.error("Factory could not create an adequate instance of Tokenizer for dtype:{} !",dtype.name());
        }
        return new DefaultTokenizer();
    }
}

您可以将Tokenizer(s)的界面定义为:

public interface ITokenizer {
    public void tokenizeData(Filename datablob);
}

...由您的抽象类AbstractTokenizer实现,所有子类(例如TokenizerV1TokenizerV2)将仅重新定义自定义抽象方法。就像下面的示例(基于@Lucas Oliveira提案)一样:

public abstract class AbstractTokenizer implements ITokenizer {
    @Override
    public void tokenizeData(Filename datablob) {
        // convert filename
        // open file
        // handle file errors
        // other code

        tokenizedData = tokenizer( data );

        // parsing and collection code
        // more error processing code
        // cleanup code
    }
    abstract TokenizedData tokenizer( Data cleansedData );  // << redef. by subclasses.
}

但它对你来说是透明的。

您最终可以使用TokenizerFactory,只需为主要业务方法提供一个预配置的参数,或者即使您拥有参数化所需的参数,也可以即时使用它们。因此,getInstance()调用将返回您需要'tokenizeData()'的确切Tokenizer

注意:对于高度参数化的工厂,将它们与Builder(模式)相结合通常可以节省生命。

答案 1 :(得分:0)

Template Method似乎正在寻找什么。

它让你:

  • 在操作中定义算法的框架,将一些步骤推迟到客户端子类。模板方法允许子类重新定义算法的某些步骤而不改变算法的结构。

  • 基类声明算法'占位符',派生类实现占位符。

这是通过Abstract类完成的。您应该确定算法的哪些步骤是不变的(或标准的),哪些是变体的(或可定制的)。不变步骤在抽象基类中实现,而变量步骤可由oncrete派生类提供。

在你的情况下,事情就是这样:

abstract class AbstractTokenizer {
    public void tokenizeData(final Object datablob) {
        // convert filename
        // open file
        // handle file errors
        // other code

        tokenizedData = tokenizer( cleansedData );

        // parsing and collection code
        // more error processing code
        // cleanup code
    }
    abstract TokenizedData tokenizer( Data cleansedData );
}