在Abstract Class中强制执行方法执行顺序

时间:2014-09-30 16:30:23

标签: java oop design-patterns abstract-class

我有一个商业案例,其中有三件事需要按顺序发生:

  1. 下载()
  2. 处理()
  3. 上传()
  4. 现在,Abstract Class FileTransfer提供1. downloadFiles()和3. upload()的实现,但不提供2. process() - 子类(如MusicFileTransfer或VideoFileTransfer或PDFFileTransfer)将执行不同的操作在2. process()阶段。

    因此,使抽象类如此清晰似乎很明显:

    public abstract class FileTransfer {
    
    public void download() {
        // implementation provided
    }
    
    public abstract void process(); // implementation not provided
    
    public void upload() {
        // implementation provided
    }
    
    }
    

    但是有一个问题 - 永远不会 是一个可以让MusicFileTransfer在下载之前调用process()的时间。 )或任何其他订单。该过程必须始终为1. download(),2。process(),然后3. upload()。

    所以我想象的是:

    public void doTransfer() {
        // private methods since we want to enforce this order of execution
        download(); // implem provided
        process(); // abstract method
        upload(); // implem provided
    }
    
    在FileTransfer中

    来回绕这三个调用。 但是为了让子类MusicFileTransfer覆盖process()......它必须是公共的或受保护的(不是私有的)。

    我应该怎么做才能解决这个问题?有一个公共的doTransfer()一个公共进程(),并确保永远不会调用process()?或者取消doTransfer()并希望订单总是正确的?

5 个答案:

答案 0 :(得分:4)

您需要template method pattern。在doTransfer类中创建final方法(FileTransfer),该方法定义了需要调用的方法的顺序。同时设置downloadupload方法final,这样它们就无法被覆盖。 process方法是abstract方法;使它成为protected因此无法从其他类调用它。它不能是public,否则可能会被其他一些类无序调用。

public final void doTransfer() {
    // protected methods since we want to enforce this order of execution
    download(); // implem provided
    process(); // abstract method
    upload(); // implem provided
}
protected final void download() {
    // implementation provided
}

protected abstract void process(); // implementation not provided

protected final void upload() {
    // implementation provided
}

然后子类只能实现process方法,并且它们不能覆盖任何其他方法。

答案 1 :(得分:1)

如果扩展FileTransfer的所有类都在同一个包中,您可以设置download()upload()process()个受保护的方法。这样你就可以限制谁可以打电话给他们。

然后保持模板方法doTransfer()公开,这是外部类(包外)可以调用的唯一方法

我还会添加一个javadoc注释,指定只应调用doTransfer()

像这样:

public abstract class FileTransfer {

    /**
     * Handles the file transfer process
     */
    public void doTransfer() {
        // private methods since we want to enforce this order of execution
        download(); // implem provided
        process(); // abstract method
        upload(); // implem provided
    }

    /**
     * Invoking outside of doTransfer can cause unexpected behavior.
     */
    // If you never want subclasses to override this, make it private
    protected void download() {
        // implementation provided
    }

    /**
     * Invoking outside of doTransfer can cause unexpected behavior.
     */
    // If you never want subclasses to override this, make it private
    public void upload() {
        // implementation provided
    } 

    /**
     * Invoking outside of doTransfer can cause unexpected behavior.
     */
    // Only the subclasses in the same package will be able to access this
    // for implementation purposes
    protected abstract void process(); // implementation not provided
}

您使用班级的方法的API将只是

FileTransfer
    void doTransfer()  
        Handles transfering the files etc...

API中不应提供其他任何方法。

注意: 但是,实现process()的子类仍然可以调用它。没有办法完全阻止他们这样做。您可以做的最好的事情是添加文档,指明不鼓励它。

另一个问题是,因为您不知道子类实际上是如何实现process()的,所以您无法肯定地说它不能单独调用。您只是假设他们以您期望的方式实现它会导致其行为不正确。

答案 2 :(得分:1)

在这种情况下,您可能会考虑使process()方法受到保护,这意味着子类可以扩展它,但消费者可能不会直接调用它。另外,也许download()和upload()方法也不应该公开。请考虑以下事项:

public abstract class FileTransfer {

    private void download() {
        // implementation provided
    }

    protected abstract void process(); // implementation not provided

    private void upload() {
        // implementation provided
    }

    public void doTransfer() {
        // private methods since we want to enforce this order of execution
        download(); // implem provided
        process(); // abstract method
        upload(); // implem provided
    }

}

示例实现类:

public class FTPFileTransfer {

    protected void process() {
        // implement FTP file transfer here

    }
}

样本消费者方法:

public void consumerMethod() {
    FileTransfer fileTransfer = factory.getFTPFileTransfer();
    fileTransfer.doTransfer();
} 

答案 3 :(得分:0)

process()方法是否可以受到保护?

答案 4 :(得分:0)

这里的典型方法是跟踪状态,这样如果其中一个方法被无序调用,你就会抛出IllegalStateException - 但是如果你的抽象方法process是这里的话逻辑是实现的,当然你不会有这种控制。

final void process() {
    if (state != DOWNLOAD) throw new IllegalStateException("Download must be invoked first");
    ...

可能的解决方案是采用类似于java.lang.Thread的方法,其中调用者调用start并且实现者覆盖run。然后你可以公开让我们说doProcess作为你的抽象方法,当你的调用者调用process时调用它:

void process() { // from base-class
    if (state != DOWNLOAD) throw new IllegalStateException("Download must be invoked first");
    doProcess();
}

final void doProcess() { // implementing abstract method
    // implementation logic here

或者,对于您的客户端代码可能是最新的,尽管可能需要更多的样板,但是可以使用'委托':将原始基类子类化为保持调用可靠性的委托者你的实现类:

class FileTransferDelegator extends FileTransfer {

    final Filetransfer delegate;

    FileTransferDelegator(Filetransfer delegate) {
        this.delegate = delegate;
    }

    void process() {
        if (state != DOWNLOAD) throw new IllegalStateException("Download must be invoked first");
        delegate.process();
    }