什么是扩展功能的最佳方式?

McG*_*one 9 java

我遇到了一个扩展给定类功能的情况,但我不确定最好的方法.我开始调用"向上"功能,现在切换到"向下",但我看到两者都有问题.让我解释一下我的意思.首先,"向上"的方法:

public class ParentValidator
{
    public void validate() {
        // Some code
    }
}

public class ChildValidator extends ParentValidator
{
    @Override
    public void validate() {
        super.validate();
        // Some code
    }
}

public class GrandchildValidator extends ChildValidator
{
    @Override
    public void validate() {
        super.validate();
        // Some code
    }
}
Run Code Online (Sandbox Code Playgroud)

这个功能非常好,但它要求我总是记得在我的方法体中放置super.validate()或者不会执行父类中的逻辑.此外,由于子类实际上可以替换/修改父类中定义的代码,因此以这种方式扩展可以被认为是"不安全的".这就是我称之为"向上"调用方法的原因,因为我正在调用更高级别的方法.

为了解决这些不足,我决定让ParentValidator.validate()最终并让它调用一个不同的方法.这是我的代码被修改为:

public class ParentValidator
{
    public final void validate() {
        // Some code

        subValidate();
    }

    protected void subValidate() {}
}

public class ChildValidator extends ParentValidator
{
    @Override
    public final void subValidate() {
        // Some code

        subSubValidate();
    }

    protected void subSubValidate() {}
}

public class GrandchildValidator extends ChildValidator
{
    @Override
    public void subSubBalidate() {
        // Some code

        subSubSubValidate();
    }

    protected void subSubSubValidate();
}
Run Code Online (Sandbox Code Playgroud)

这就是我所说的当我说我向下调用时,因为每个类调用继承链"向下"类的方法.

使用这种方法,我可以保证将执行父类中的逻辑,我喜欢.但是,它不能很好地扩展.我拥有的层次越多,它就越丑陋.在某种程度上,我觉得这很优雅.在两个层面上,它开始变得粗制滥造.在三个或更多,它是可怕的.

另外,就像我必须记得调用super.validate()作为我孩子的任何验证方法的第一行一样,我现在必须记住在我父亲的任何验证方法的末尾调用一些"subValidate"方法. ,所以似乎没有变得更好.

有没有更好的方法来进行我甚至没有涉及的这种类型的扩展.这两种方法都有一些严重的缺陷,我想知道我是否有更好的设计模式.

Edw*_*rzo 4

在您所描述的第一种方法中,您使用的是简单继承,第二种方法更接近四人帮[GoF] 所谓的模板方法模式,因为您的父类正在使用所谓的好莱坞原则“不要给我们打电话,我们就会给您打电话”

但是,您可以通过在父类中将 subvalidate() 方法声明为抽象方法来受益,这样可以确保所有子类都强制实现它。那么这将是一个真正的模板方法。

public abstract class ParentValidator
{
    public final void validate() {
        //some code
        subValidate();
    }
    protected abstract void subValidate() {}
}
Run Code Online (Sandbox Code Playgroud)

根据您正在做的事情,还有其他模式可以帮助您以不同的方式完成此任务。例如,您可以使用策略模式来执行验证,并且通过这种方式有利于组合而不是继承,如之前所建议的,但结果是您将需要更多的验证类。

public abstract class ParentValidator
    {
        private final ValidatorStrategy validator;

        protected ParentValidator(ValidatorStrategy validator){
           this.validator = validator;
        }

        public final void validate() {
            //some code
            this.validator.validate();
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后,您可以为您拥有的每种类型的验证器提供特定的验证策略。

如果您想两全其美,您可能会考虑将解决方案实现为装饰器模式,其中子类可以扩展父类的功能,但仍然坚持通用接口。

public abstract class ValidatorDecorator implements Validator
        {
            private final Validator validator;

            protected ParentValidator(Validator validator){
               this.validator = validator;
            }

            public final void validate() {
                //some code
                super.validate(); //still forced to invoke super
                this.validator.validate();
            }
        }
Run Code Online (Sandbox Code Playgroud)

所有模式都有后果和优点和缺点,您必须仔细考虑。