我有一个商业案例,其中有三件事需要按顺序发生:
现在,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()并希望订单总是正确的?
答案 0 :(得分:4)
您需要template method pattern。在doTransfer
类中创建final
方法(FileTransfer
),该方法定义了需要调用的方法的顺序。同时设置download
和upload
方法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();
}