views:

54

answers:

3

i'm working on a fork of the Divan CouchDB library, and ran into a need to set some configuration parameters on the httpwebrequest that's used behind the scenes. At first i started threading the parameters through all the layers of constructors and method calls involved, but then decided - why not pass in a configuration delegate?

so in a more generic scenario,

given :

class Foo {
    private parm1, parm2, ... , parmN
    public Foo(parm1, parm2, ... , parmN) {
        this.parm1 = parm1;
        this.parm2 = parm2;
        ...
        this.parmN = parmN;
    }

    public Bar DoWork() {
        var r = new externallyKnownResource();
        r.parm1 = parm1;
        r.parm2 = parm2;
        ...
        r.parmN = parmN;
        r.doStuff();
    }
}

do:

class Foo {
    private Action<externallyKnownResource> configurator;
    public Foo(Action<externallyKnownResource> configurator) {
        this.configurator = configurator;
    }

    public Bar DoWork() {
        var r = new externallyKnownResource();
        configurator(r);
        r.doStuff();
    }
}

the latter seems a lot cleaner to me, but it does expose to the outside world that class Foo uses externallyKnownResource

thoughts?

+2  A: 

This can lead to cleaner looking code, but has a huge disadvantage.

If you use a delegate for your configuration, you lose a lot of control over how the objects get configured. The problem is that the delegate can do anything - you can't control what happens here. You're letting a third party run arbitrary code inside of your constructors, and trusting them to do the "right thing." This usually means you end up having to write a lot of code to make sure that everything was setup properly by the delegate, or you can wind up with very brittle, easy to break classes.

It becomes much more difficult to verify that the delegate properly sets up each requirement, especially as you go deeper into the tree. Usually, the verification code ends up much messier than the original code would have been, passing parameters through the hierarchy.

Reed Copsey
in the general case, i agree, but what about when you're dealing with a know entity? i'm configuring an httpwebrequest here. the more work i do with the library, the more random little things i need to drag inside. first it was http auth, now it's proxy settings. the web request is already self-validating, with (somewhat) sensible error codes.
kolosy
If it's something you're doing internally, I find it less problematic. Just don't expose it to a public API....
Reed Copsey
A: 

IMO, you're best off accepting a configuration object as a single parameter to your Foo constructor, rather than a dozen (or so) separate parameters.

Edit:

there's no one-size-fits-all solution, no. but the question is fairly simple. i'm writing something that consumes an externally known entity (httpwebrequest) that's already self-validating and has a ton of potentially necessary parameters. my options, really, are to re-create almost all of the configuration parameters this has, and shuttle them in every time, or put the onus on the consumer to configure it as they see fit. – kolosy

The problem with your request is that in general it is poor class design to make the user of the class configure an external resource, even if it's a well-known or commonly used resource. It is better class design to have your class hide all of that from the user of your class. That means more work in your class, yes, passing configuration information to your external resource, but that's the point of having a separate class. Otherwise why not just have the caller of your class do all the work on your external resource? Why bother with a separate class in the first place?

Now, if this is an internal class doing some simple utility work for another class that you will always control, then you're fine. But don't expose this type of paradigm publicly.

Randolpho
that doesn't solve the original issue.
kolosy
No, it does not. There is no solution to your issue, is the point I was trying to make. You are best off not exposing "externallyKnownResource"
Randolpho
there's no one-size-fits-all solution, no. but the question is fairly simple. i'm writing something that consumes an externally known entity (httpwebrequest) that's already self-validating and has a *ton* of potentially necessary parameters. my options, really, are to re-create almost all of the configuration parameters this has, and shuttle them in every time, or put the onus on the consumer to configure it as they see fit.
kolosy
i'm not sure i agree that's it's poor class design. i still have an issue with duplicating the configuration properties of a substantially-configurable class for the sake of 'that one' property that someone may need. It may be better to externalize the connection creation entirely.
kolosy
@kolosy: it sounds like @dnewcome's answer is the correct one, then. Have the user of the class provide a properly configured ExternallyKnownResource for Foo to work on.
Randolpho
+1  A: 

I may be missing something here, but it seems like a big disadvantage to create the externallyKnownResource object down in DoWork(). This precludes easy substitution of an alternate implementation. Why not:

public Bar DoWork( IExternallyKnownResource r ) { ... }
dnewcome
because externallyKnownResource in this case is an httpwebrequest which is already factoried by (uh... no, that's not a word, but it fits) the WebRequest.Create() method via the url scheme
kolosy