
Question:
I have a property called "IsSecureConnection" that is part of my object's interface. This makes sense for most implementations of the interface, however, in some implementations I would like to make the property ReadOnly.
Should I omit this property from the object's interface even though it is required by all of the implementations (though slightly different on occasion)?
Thanks!
Answer1:It really depends on what's most readable for your clients. I can think of a couple of options:
1) The inherited interface, though I'm not a fan of hiding, and I think it makes it a bit ugly for any VB.NET or explicit clients to implement:
interface IObject {
bool IsSecureConnection { get; }
// ... other interface definitions //
}
interface ISecurableObject : IObject {
new bool IsSecureConnection { get; set; }
}
2) Split the set from the property, with an inherited interface:
interface IObject {
bool IsSecureConnection { get; }
// ... other interface definitions //
}
interface ISecurableObject : IObject {
void SetConnectionSecurity(bool isSecure);
}
3) Changing the semantics to <em>try</em> and acquire a secure connection, which an implementer is free to just return false from:
interface ISecurable {
bool IsSecureConnection { get; }
bool TrySecureConnection();
}
4) Add an additional check property:
interface ISecurable {
bool IsSecureConnection { get; set; }
bool SupportsSecureConnection { get; }
}
All of these are, IMO, valid designs for certain contexts. Since I don't have any info on the use cases, except that almost all of the time a secure connection can be established - I'd probably vote for 3. It's easy to implement, there's only 1 code path for clients, and there's no exception mechanism (which is another form of coupling). You do have the danger of clients not checking the return from TrySecureConnection, but I think it has less issues than the other choices.
If clients <em>prefer</em> a secure connection, but don't <em>require</em> one - then 1 has the disadvantage of either requiring overloads or the client to check if their IObject is really a ISecurableObject. Both of which are kind of ugly. 2 has the same problem, but without the troublesome new/shadows trickery. However, if some clients require a secure connection, then this (or 2) is probably the way to go - otherwise, you can't really use type safety to enforce a securable connection.
4, while a valid design IMO (some would disagree - see reactions to IO.Stream) is easy for clients to get wrong. If 90% of implementers are securable, it's easy to not check the SupportsSecureConnection. There's also an implementer's choice of either throwing an exception or discarding the IsSecureConnection = true call if it's not supported, requiring clients to both catch and check the new value of IsSecureConnection.
Answer2:Just add the getter in the interface.
public interface Foo{
bool MyMinimallyReadOnlyPropertyThatCanAlsoBeReadWrite {get;}
}
Interfaces specify the minimum an object must implement; it doesn't say what an object cannot do. For that, you need to look into creating base classes.
Answer3:Interfaces are like salt : sprinkle them everywhere:
public interface ICanBeSecure
{
bool IsSecureConnection { get; }
}
public interface IIsSecureable : ICanBeSecure
{
bool IsSecureConnection { get; set;}
}
Answer4:You need to evaluate the case. If it doesn't make sense to have it always be writeable, separate it into a second interface.
public interface IFoo {
bool SecuredConnection{ get; }
}
public interface ISecurableOptionFoo: IFoo {
bool SecuredConnection{ get; set; }
}