假设我们想在一个接口模式中分离出读写访问,如下所示。
namespace accesspattern
{
namespace ReadOnly
{
public interface IA { double get_a(); }
}
namespace Writable
{
public interface IA : ReadOnly.IA { void set_a(double value); }
}
}
这很容易实现:
namespace accesspattern
{
namespace ReadOnly
{
public class A : IA
{
protected double a;
public double get_a() { return a; }
}
}
namespace Writable
{
public class A : ReadOnly.A, IA
{
public void set_a(double value) { base.a = value; }
}
}
}
假设我们需要另一个继承自 A 的类,因此我们继续为它定义一个接口:
namespace accesspattern
{
namespace ReadOnly
{
public interface IB : ReadOnly.IA { int get_b(); }
}
namespace Writable
{
public interface IB : ReadOnly.IB, Writable.IA { void set_b(int value); }
}
}
实现这一点并不容易。总觉得Writable.B应该继承Writable.A和ReadOnly.B这两个基类,避免重复代码。
有推荐的设计模式吗?目的是能够根据要求分别返回“只读访问”和“读写访问”对象(在编译时决定)。如果解决方案模式可以很容易地添加更多的继承层,C、D 类......
我知道多重继承的问题在这里突然出现,并且已经在很多很多地方的其他地方详细讨论过。但我的问题不是“如何在不使用多重继承的情况下实现命名空间访问模式中定义的接口”(尽管我想学习最好的方法),而是我们如何定义只读/可写一个类的不同版本,并且还支持继承而不会变得非常非常混乱?
对于这里值得的是一个(混乱的)解决方案[见下文以获得更好的实现]:
namespace accesspattern
{
namespace ReadOnly
{
public class A : IA
{
protected double a;
public double get_a() { return a; }
}
public class B : IB
{
protected int b;
public int get_b() { return b; }
}
}
namespace Writable
{
public class A : ReadOnly.A, IA
{
public void set_a(double value) { base.a = value; }
}
public class B : ReadOnly.B, IB
{
private IA aObj;
public double get_a() { return aObj.get_a(); }
public void set_a(double value) { aObj.set_a(value); }
public void set_b(int value) { base.b = value; }
public B() { aObj = new A(); }
}
}
}
}
更新:我认为这(下)是尤金所说的。我认为这种实现模式非常好。通过只传递类的“writeProtected”视图,可以实现要求类的状态不会改变的算法,并且只使用“writeEnabled”视图,这意味着该函数将/可能导致状态避免的变化。
namespace access
{
// usual usage is at least readable
public interface IA { double get_a(); }
public interface IB : IA { int get_b(); }
// special usage is writable as well
namespace writable
{
public interface IA : access.IA { void set_a(double value); }
public interface IB : access.IB, IA { void set_b(int value);}
}
// Implement the whole of A in one place
public class A : writable.IA
{
private double a;
public double get_a() { return a; }
public void set_a(double value) { a = value; }
public A() { }
//support write-protection
public static IA writeProtected() { return new A(); }
public static writable.IA writable() { return new A(); }
}
// implement the whole of B in one place and now no issue with using A as a base class
public class B : A, writable.IB
{
private int b;
public double get_b() { return b; }
public void set_b(int value) { b = value; }
public B() : base() { }
// support write protection
public static IB writeProtected() { return new B(); }
public static writable.IB writable() { return new B(); }
}
public static class Test
{
static void doSomething(IA a)
{
// a is read-only
}
static void alterState(writable.IB b)
{
// b is writable
}
static void example()
{
// Write protected
IA a = access.A.writeProtected();
IB b = access.B.writeProtected();
// write enabled
writable.IA A = access.A.writable();
writable.IB B = access.B.writable();
Console.WriteLine(a.get_a());
B.set_b(68);
doSomething(A); // passed as writeprotected
alterState(B); // passed as writable
}
}
}