views:

32

answers:

1

I am working on an ASPX page that needs to handle multiple different kinds of data. I came up with a potentially ideal fashion to fetch the information I need, but am unsure if it is as good an idea as it feels. Basically, I need to filter a set into a subset, but which values I filter by will differ by circumstance. I constructed the following code snippet that seems to work fine.

List<string> lStr = new List<string>() {
    "Category",
    "Document Number", //Case 1 Only
    "Document Title", //Case 1 Only
    "Picture Title", //Case 2 Only
    "Picture Number", //Case 2 Only
    "Issue",
    "Issue Date",
    "Issue Title",
    "Notes",
    "High Priority" //Case 1 Only
};
AddControls(bigDataInput.Fields.OfType<FieldObject>().Where(x => lStr.Contains(x.Title)).ToArray());

bigDataInput is an object that has a property called Fields, which is a Collection of objects called FieldObject. I need to get a subset of these FieldObjects based on their title, and pass all of them into a method AddControls(params FieldObject[] fields). The issue is that which titles I need to filter by will differ based on the bigDataInput itself. There are only two case scenarios currently, and these are the fields I need to filter out.

  • bigDataInput Case 1: Category, Document Number, Document Title, Issue, Issue Date, Issue Title, Notes, High Priority
  • bigDataInput Case 2: Category, Picture Title, Picture Number, Issue, Issue Date, Issue Title, Notes

The bigDataInput will have additional fields besides those that I need. However, the field collection will only have one of the filtered fields if and only if I will actually need the field for that particular case. For example, Case 1 does not have the Picture Title and Picture Number fields, and Case 2 does not have the Document Number, Document Title, and High Priority fields. This restriction will also apply to all future cases, however many there might be.

I at first considered constructing a List based on the specific case scenario, but the switch case to build it could get quite large, and repetitive to a degree. That's when I came up with the idea for the above code snippet. But is this actually a good idea? Or is there a better method than this but much more concise than a potentially humongous switch case?

+1  A: 

It's hard to wrap my head around your exact issue, but from what it got it might make sense to attack this a little differently using some design patterns. One that comes to mind that might make sense is the Strategy pattern. Basically, this is a way of encapsulating the algorithm (logic) from its host.

Wikipedia has an entry on the Strategy pattern here: http://en.wikipedia.org/wiki/Strategy_pattern

I'm thinking about a flow somewhat like this:

  • You have an interface called IDataInputTransformer with 2 methods: bool AcceptsInput(bigDataInput i) and FieldObject[] TransformInput(bigDataInput i)

  • The calling class has an IEnumerable of IDataInputTransformers that is set somehow -- either manually on instantiation or using dependency injection or something

  • Upon being passed a bigDataInput, the calling class iterates over each IDataInputTransformer and calls AcceptsInput with the bigDataInput. If the input is not accepted it just tries the next & the next (if none accept the input perhaps an exception is thrown or something). If it the IDataInputTransformer does accept the input then you can call TransformInput and get the FieldObject[] that will be passed to AddControls

You could take this further, but this is the basic idea. The benefits here are:

  • Readability -- it's really easy to read FinanceDepartmentInputTransformer.TransformInput(), it's really hard to read a huge switch
  • Able to change -- you can add new InputTransformers easily (and it won't ruin the readability or functionality)
  • Rules are isolated -- you can easily check the business rules in the AcceptsInput methods
  • Portability -- you could use this elsewhere too
  • Testability -- you can easily unit test this to make sure it works right
statichippo
I like your concept. To clarify, though, I'm hoping to avoid the tedium of having to define the required subset for a given bigDataInput (the defining of several TransformInputs in your Strategy), because there is a lot more overlap between subsets than exclusivity. Your method is much superior than a giant switch case, so I would use this if my current method is a bad idea.
ccomet
Whether or not I implement this for this specific situation, I will look into using this for a few other parts of my application.
ccomet
The fact that there's a lot of overlap shouldn't make much of a difference. The AcceptsInput method can just check for the simplest passing constraint. As for the TransformInput method, if you use a base class you can remove any redundancy. At that point, I'm not sure you'd have any more code than a large switch statement, but you'd protect yourself a bit more.
statichippo
I'm not worried about AcceptsInput, there's a variable in bigDataInput which tells me which case it is. The only concern regarding using a base class is that order of the strings wouldn't be maintained directly, since the exclusive fields can be located anywhere. This could be mitigated by using, say, a LinkedList and its AddAfter. It'd be clunky, but would save on repeating the vast number of redundant fields in each case.
ccomet