50446

Should this property be part of my object's interface?

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; } }

Recommend

  • Is there any provision in android to know which user application is using which system service
  • Why do some methods use dot notation and others don't?
  • How to create a Plone 4 group who's sole purpose is to manage users?
  • What happens when you initialize a parameter? C++
  • Scala: Example use for early definition / early initializer / pre-initialized fields
  • Cast uint -> double invalid?
  • TelephonyManager crashing on android studio
  • Using Regex to split XML string before and after match
  • How to make a dictionary from a text file with python
  • What to use (best/good practice) for the secret key in HMAC solution?
  • IIS7 Application Request Routing HTTPS
  • Delete ARP entry on Windows CE 6.0 CF.NET 2.0
  • .htaccess mod rewriterule and ampersands
  • Android Studio cannot find resources when building for device with version > 5.0
  • How to write xml into a file using MarkupBuilder
  • Table-per-type inheritance insert problem
  • How to bind comma separated list of values to List
  • How to split row into many rows in postgresql
  • How can I count unique terms in a plaintext file case-insensitively?
  • Python: Split a String Field into 3 Separate Fields using Lambda
  • how can I compare dates in array to find the earliest one?
  • Divide a $1 by 3 and adjusting 1 cent
  • How do I shift the decimal place in Python?
  • DIV instruction jumping to random location?
  • Check for zero lines output from command over SSH
  • nonblocking BIO_do_connect blocked when there is no internet connected
  • MailKit: The IMAP server replied to the 'EXAMINE' command with a 'BAD' response
  • why overloaded new operator is calling constructor even I am using malloc inside overloading functio
  • JavaScriptCore crash on iOS9
  • Can I have the cursor start on a particular column by default in jqgrid's edit mode?
  • Display Images one by one with next and previous functionality
  • sending mail using smtp is too slow
  • Checking variable from a different class in C#
  • costura.fody for a dll that references another dll
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • Binding checkboxes to object values in AngularJs
  • How can I use `wmic` in a Windows PE script?
  • failed to connect to specific WiFi in android programmatically
  • How to push additional view controllers onto NavigationController but keep the TabBar?
  • How can I use threading to 'tick' a timer to be accessed by other threads?