Skip to main content
Elaborated on the value of a class that can be incomplete upon initialization.
Source Link

I think that the two problems you listed arise not from your design but rather out of the problem you are solving.

Depending on how generic you want to make your design, you could have some meta-data that defines each major processing step, and then some methods that you call to "push" the pipeline into the next step. Of course, since it sounds like each step requires its own specific parameters from the user, you would have to define the parameters generically as well, using more meta-data.

I don't think that what I just outlined is a particularly good design based on your problem description. It adds a lot of complexity and meta-data overhead for no real benefit. Sometimes a problem is so domain-specific that the code you design to solve it is going to be equally specialized. That's not necessarily a bad thing. You can mitigate it by writing code that is as clear and simple and well-documented as possible :-)

Update: As to your specific question of whether it's "OK to have a have a class that's designed to be incomplete on initialization, and completed by necessary processing steps," you may be thinking of the more general advice that is mentioned in some OO design guidelines:

A properly written constructor leaves the resulting object in a valid state.

Remember, it's up to you to decide what "valid" actually means in context. In your example, I would argue that the CommunityGraphSet is in a valid state even at the beginning because its purpose is not to serve as a static immutable representation of the graphs, but as a processing pipeline to generate the graphs based on successive stages of user input. In other words, it's not really "incomplete" because the requirements dictate that the processing requires several stages of user input. Perhaps a better name would be CommunityGraphGenerator or CommunityGraphProcessor. Further, you could define a separate class CommunityGraphSet that would hold the results of the entire process once the pipeline is finished. Even if this class is just contained within the larger one, it might make the design more understandable to an OO purist.

I think that the two problems you listed arise not from your design but rather out of the problem you are solving.

Depending on how generic you want to make your design, you could have some meta-data that defines each major processing step, and then some methods that you call to "push" the pipeline into the next step. Of course, since it sounds like each step requires its own specific parameters from the user, you would have to define the parameters generically as well, using more meta-data.

I don't think that what I just outlined is a particularly good design based on your problem description. It adds a lot of complexity and meta-data overhead for no real benefit. Sometimes a problem is so domain-specific that the code you design to solve it is going to be equally specialized. That's not necessarily a bad thing. You can mitigate it by writing code that is as clear and simple and well-documented as possible :-)

I think that the two problems you listed arise not from your design but rather out of the problem you are solving.

Depending on how generic you want to make your design, you could have some meta-data that defines each major processing step, and then some methods that you call to "push" the pipeline into the next step. Of course, since it sounds like each step requires its own specific parameters from the user, you would have to define the parameters generically as well, using more meta-data.

I don't think that what I just outlined is a particularly good design based on your problem description. It adds a lot of complexity and meta-data overhead for no real benefit. Sometimes a problem is so domain-specific that the code you design to solve it is going to be equally specialized. That's not necessarily a bad thing. You can mitigate it by writing code that is as clear and simple and well-documented as possible :-)

Update: As to your specific question of whether it's "OK to have a have a class that's designed to be incomplete on initialization, and completed by necessary processing steps," you may be thinking of the more general advice that is mentioned in some OO design guidelines:

A properly written constructor leaves the resulting object in a valid state.

Remember, it's up to you to decide what "valid" actually means in context. In your example, I would argue that the CommunityGraphSet is in a valid state even at the beginning because its purpose is not to serve as a static immutable representation of the graphs, but as a processing pipeline to generate the graphs based on successive stages of user input. In other words, it's not really "incomplete" because the requirements dictate that the processing requires several stages of user input. Perhaps a better name would be CommunityGraphGenerator or CommunityGraphProcessor. Further, you could define a separate class CommunityGraphSet that would hold the results of the entire process once the pipeline is finished. Even if this class is just contained within the larger one, it might make the design more understandable to an OO purist.

Source Link

I think that the two problems you listed arise not from your design but rather out of the problem you are solving.

Depending on how generic you want to make your design, you could have some meta-data that defines each major processing step, and then some methods that you call to "push" the pipeline into the next step. Of course, since it sounds like each step requires its own specific parameters from the user, you would have to define the parameters generically as well, using more meta-data.

I don't think that what I just outlined is a particularly good design based on your problem description. It adds a lot of complexity and meta-data overhead for no real benefit. Sometimes a problem is so domain-specific that the code you design to solve it is going to be equally specialized. That's not necessarily a bad thing. You can mitigate it by writing code that is as clear and simple and well-documented as possible :-)