Reputation: 2751
Which would be a better design for a public interface:
WriteValue(DeviceValueType.MachineName,"micks machine");
OR
WriteMachineName("Micks machine");
If you use type 1 then you just need one such generic interface and you can write to any number of DeviceValueTypes just by adding items to the enum.
The second type is more specific in that it will write only a value to specific type denoted by its method name. But these methods have a great advantage with respect to type safety.
For eg: Lets consider another type
WriteValue(DeviceValueType.SleepDelay,"25");
and
WriteSleepDelay(25);
Note that here, type 2 has an advantage because I can specify the type expected. If I were to use type 1 then I will have to cast the value to int and then throw an exception if the value is not in the expected range. If I had to pass complex types, this becomes even more difficult.
So in summary:
Type 1: Generic. The interface will need to expose only one method. No type safety for parameters. Type 2: Specific. The interface will require as many methods as there are types. Type safe.
What is the generally suggested methodology to solve this problem?
I am using C# but I believe this problem to be non language specific.
Upvotes: 3
Views: 500
Reputation: 19987
You should avoid what you call type 1 interfaces. Speaking from experience, these kind of interfaces tend to get messy pretty fast. Take the sleep delay example. How are you going to type check that string for a positive integer? You will end up with a huge switch statement. So at the very least encapsulate it.
Although your type 2 is better it should be noted that it tightly couples the write action with the data needed for the write. I don't know the requirements you are dealing with (write once read many?), but your DeviceValueType enum suggests you could simply declare a DeviceConfig class with properties like machine name
and sleep delay
and pass that to a Device or DeviceWriter class that will do the actual work. However, if machine name
is config, while sleep delay
is actually a method you should consider separating those two concerns as well (i.e. Device.sleep() and Device.writeConfig(DeviceConfig)).
Upvotes: 1
Reputation: 1994
First of all: I don't know a general rule, or a design-pattern for that situation, therefore I write what I would do.
If you don't care about the parameter's type, do something like this WriteValue("micks machine");
. But than don't do any tricks like formatting integer differntly than strings, etc., just plain write the string you get and let the caller do translations. (type 0)
I would never do something like your type 1. Why? you mentioned some reasons (type-safety). But also for readability: you would end up doing swtiches or if-then-elses. And, if you care about clean code, you would also end up writing private helper methods with a signature like WriteMachineName("Micks machine");
(as in type 2).
I would prefer type 2, maybe mixed with type 0 for simple types, e.g. WritePlain("Micks machine"); WriteNumber(3.4);
Note: in type 1 and 2, you move some of your business code to those methods. That's neither good nor bad, but you must choose if it is applicable for your case (coherence). In contrast type 0 keeps the transformation-logic from a type to a string within that class.
Upvotes: 0
Reputation: 1580
It depends :)
Also, a third possibility would be to do both: Have a generic WriteValue()
and a specific 'WriteSleepDelay()which in turn calls
WriteValue()` with the correct parameters. This can make sense if the implementation of these methods is rather complex, i.e. if you'd have much redundant code unless you concentrate it into the generic method.
For a (presumably) simple thing like WriteValue
I'd go with separate methods for simplicity.
Update: For an inheritance hierarchy it would make sense to have the generic method in the base interface. The derived classes can then add additional type-safe methods (e.g. WriteSleepDelay()
) that make sense for them only.
Or you might want to have a WriteValue(Object value)
in the base class that's overridden with an appropriate typesafe variant in the children (e.g. WriteValue(Integer)
in child class SleepTimer
). Most likely this won't make sense in your concrete case, but for other situations it can be ideal.
Upvotes: 0
Reputation: 439
I'm coming from a Python background, but I would actually pick both options. Make the WriteValue function, and let it do all the heavy lifting. Then, write the WriteMachineName and WriteSleepDelay functions as simple wrappers around WriteValue. This way, you'll be able to use the shorthand function for all functions that are used often, and the long version for everything that isn't called that often.
You might want to make the way this works explicit in the documentation though, so people who'll have to work with it after you know how and why you did this.
Also: I don't know how expensive function calls are in C#. If they are very expensive (in CPU time), you might want to always go with type 1.
Upvotes: 1