我有一个场景,我当前的界面看起来像
public interface IMathematicalOperation
{
void AddInt();
}
一年之后,我希望界面能够通过 AddFloat 方法进行扩展,并且还希望有100个用户使用此界面。当我在一年之后使用新方法扩展界面时,我不希望这100个类被更改。 那么我该如何解决这种情况呢?有没有可用的设计模式来处理这种情况?
注意:我知道我可以有一个抽象类来实现这个接口并使所有方法都是虚拟的,这样客户端就可以继承这个类而不是接口并覆盖方法。当我添加一个新方法时,只会更改抽象类,对该方法感兴趣的客户端将覆盖该行为(最小化更改)。 有没有其他方法可以实现相同的结果(比如有一个名为Add的方法,并且基于某些条件它会做Float加法或整数加法)?
修改1:
新方法被添加到界面中也需要与现有方法一起自动调用(如责任链模式)。
答案 0 :(得分:1)
我能想到至少有两种可能的解决方案:
从旧界面导出新界面
public interface IMathematicalOperation
{
void AddInt();
}
public interface IFloatingPointMathematicalOperation : IMathematicalOperation
{
void AddFloat();
}
只需一个包含新方法的并行接口,并且所有需要的新接口派生的类
我建议使用第二种解决方案,因为我不明白为什么你想要一个既定的界面来改变。
答案 1 :(得分:1)
前段时间我遇到了类似的问题,发现最好的方法是不尝试扩展现有的接口,而是为每个新接口提供不同版本的接口,提供额外的功能。随着时间的推移,我发现没有定期添加功能,可能每年一次,所以添加额外的接口从来都不是问题。
因此,例如,这是您的第一个版本的界面:
public interface IMathematicalOperation
{
void AddInt();
}
此接口将在以下类上实现:
public class MathematicalOperationImpl : IMathematicalOperation
{
public void AddInt()
{
}
}
然后,当您需要添加新功能(即创建版本2)时,您将创建另一个具有相同名称的界面,但最后使用“2”:
public interface IMathematicalOperation2 : IMathematicalOperation
{
void AddFloat();
}
MathematicalOperationImpl
将扩展为实现这个新界面:
public class MathematicalOperationImpl : IMathematicalOperation, IMathematicalOperation2
{
public void AddInt()
{
}
public void AddFloat()
{
}
}
您的所有新/未来客户端都可以开始使用版本2界面,但您现有的客户端将继续工作,因为他们只会知道该界面的第一个版本。
答案 2 :(得分:0)
提供的选项在语法上是可行的,但很明显,它们不会适用于任何以前的用户。
更好的选择是使用Visitor pattern
当您考虑OO代码的详细信息时,可以最好地理解该模式
this.foo(); // is identical to
foo(this);
请记住,总有一个隐藏的'这个'每个实例调用传递的参数。 访问者模式尝试执行的操作是使用Double dispatch
来概括此行为让我们更进一步
public interface MathematicalOperation
{
void addInt();
void accept(MathVisitor v);
}
public interface MathVisitor {
void visit(MathematicalOperation operation);
}
public class SquareVistor implements MathVisitor {
void visit(MathematicalOperation operation) {
operation.setValue(operation.getValue() * 2);
}
}
public abstract class AbstractMathematicalOperation implements MathematicalOperation {
public void accept(MathVisitor f) {
f.visit(this); // we are going to do 'f' on 'this'. Or think this.f();
}
}
public class MyMathOperation extends AbstractMathematicalOperation {
}
someMathOperation.visit(new SquareVisitor()); // is now functionally equivalent to
someMathOperation.square();
最好的选择是让你用访问者的要求推出你的初始界面,然后立即推出一个抽象的子类,它提供了这个默认的实现,所以它已经被熟了(如上面的类是)。然后每个人都可以扩展它。我认为您会发现这为您提供了所需的灵活性,并使您能够使用遗留类。