Writing a method based on the value of an enumeration without falling into the smell of code

Imagine that I have a document (Word document).

I have an enumeration that will indicate how to extract data from a document. Therefore, if I need only text, images, or both (3 members of the enumeration).

I have a case statement based on this listing, but without falling into the smell of code, how can I write code that doesn't repeat too much? For each condition in the switch, should I have a separate method (the easiest way) or a method that takes a parameter (for example, an enumeration value), and then use if instructions if (xyz) execute abc, and therefore on.

Or is there a faster and more efficient way?

+3
source share
7 answers

I would use a strategy template in conjunction with a factory to create an appropriate strategy based on an enumeration value. EDIT . As others have indicated, you can also determine the right strategy using the Map. factory is my choice because it only encapsulates logic and does not require data storage.

public interface IExtractionStrategy { object Extract( Document doc ); // or what ever result is best } public class TextExtractionStrategy : IExtractionStrategy { public object Extract( Document doc ) { .... algorithm for extracting text... } } public class ImageExtractionStrategy : IExtractionStrategy { public object Extract( Document doc ) { .... algorithm for extracting images... } } public static class StrategyFactory { IExtractionStrategy GetStrategy( ExtractionEnum strategyType ) { switch (strategyType) { case ExtractionEnum.Text: return new TextExtractionStrategy(); break; case ExtractionEnum.Image: return new ImageExtractionStrategy(); break; ... } } } 
+7
source

Since it is difficult to give a general statement without knowing your exact code, I can only recommend that you read this article:

Back to the basics - Life After If, For and Switch - Like, a reminder of data structures from Scott Hanselman.

Since you only have 3 values ​​in your enumeration, any template, such as a strategy template or map, can be an architectural excess (don’t get me wrong, these templates can be very useful for large enumerations). All about choosing the right solution for a particular problem.

+3
source

Use the strategy template to separate the data processing method from its selection.

Then you can use the direct Map<Enum, Strategy> to keep the link from the enumeration to the retrieval strategy or even have a link to your own strategy in each instance of the enumeration.

+1
source

How many classes are required to change a lamp?

Perhaps this is just a terminological difference, but it seems to me a simple case when you need a distribution table:

 use constant EXTRACT_TEXT => 1, EXTRACT_IMAGES => 2, EXTRACT_BOTH => 3; my %extractor = ( (EXTRACT_TEXT) => \&extract_text, (EXTRACT_IMAGES) => \&extract_images, (EXTRACT_BOTH) => \&extract_both, ); ... die "no extractor found for $enum_value" if ! $extractor{ $enum_value }; $extractor{ $enum_value }->( $document_info ); 
+1
source

I would do (pseudo code):

 switch(enum) case images: extractImages(); break; case text: extractText(); break; case both: extractImages(); extractText(); break; 
+1
source

If you use Java enums, you can use the fact that they are actually objects:

 enum ExtractionEnum { IMAGE { public byte[] extract(InputStream is) { ... } }, TEXT { public byte[] extract(InputStream is) { ... } }; public abstract byte[] extract(InputStream is); } // ... public void doSomething(ExtractionEnum type) { byte[] data = type.extract(getInputStream()); ... } 

I'm not sure if I like it better than the strategy template or good-ol ' switch / case , but it works.

+1
source

A solution can have one class for each way you want to extract data. Each class will do all the extraction work, and they can have a common IExtract interface. You will only need to return the interface based on the enumeration, and then just call the methods on the interface.

0
source

All Articles