Smell code - which design pattern and how to implement it?

I think the following might be appropriate for the Strategy pattern, but I'm not sure if this is correct and if so how to implement it correctly.

I have a method that will accept a category and sort. Currently, category and sort are enums, something like this:

public enum Category{
  Hot,
  New
}

public enum Sort{
  New,
  Rising,      
  ThisWeek
}

public String getUrl(Category category, Sort sort){
   validateCategorySortCombo(category, sort);
}

      

Pay attention to validateCategorySortCombo (Category, Sorting). First I have to check the category + Sort combination as some of them are not valid. For example:

if(Category == "Hot" && Sort == "Rising"){
    ThrowInvalidCategorySortCombo("Can't use hot category with rising sort")
}  

      

Several of these checks will be performed to ensure that the combinations are valid. It is like a code smell because when other categories and types are introduced, I will have to open that class and change it, which would violate the open / closed principle.

The second code smell comes when I have to check both Category and Sort in order to build my Url to be passed back. I am currently using a number of switch statements:

String url;
switch(category){
  case Hot:
     url += "www.site.com/hot/";
  case New:
     url += "www.site.com/new/";
}

switch(sort){
  case New:
    url += "?sort=rising";
  case ThisYear:
    url += "?sort=thisyear";
}

      

Again, when new categories and types are introduced, I will have to open this class and update the switch statements.

A couple of questions:

  • What design pattern will be used to solve my problem?
  • How can I apply a design pattern?
+3


source to share


5 answers


First, I suggest that you leave your mind open to a few design patterns until you write some code. Let your code tell you which template will work best. If you choose one of these in front of you, you can try to "force" your code to use a template, which may not have been the best option.

Having said that, a couple of templates that you might find useful in your situation would be Strategy and Chain of Responsibility .

Moving ...

I think you need to take a step back and come up with what your design goals are based on how you expect the system to change over time. For example, it looks like you are definitely looking forward to adding new categories and sorts. Based on this, there are two goals your project might have:

  • minimize changes to the verification code when adding a new sort / category
  • minimize URL assembly code changes when adding a new sort / category

From these goals, come up with a general approach. For example, my thoughts ...



  • If I separate each validation down to my own class, I won't need to change the existing validation algorithms when adding a new category / Sort. All I have to do is add a new validation algorithm, or possibly delete an existing one if it no longer applies. (This may be overkill, but I don't know how complex your validation algorithms are or will be obtained).
  • If each category / Sort knows how to provide its own URL snippet, each new category or sort should not affect the ability to get URL representations of existing categories or views.

Now you can start thinking more about implementation (where you have a lot of options). For example, you can extend your enums so that each value already knows its url component like this:

public enum Sort{
  New("?sort=new"),
  Rising("?sort=rising"),      
  ThisWeek("?sort=thisweek");


  private String urlComponent;
  public Sort(String urlComponent) {this.urlComponent = urlComponent;)
  public getUrlComponent() {return this.urlComponent;}
}

      

By going this route you can always call mySort.getUrlComponent()

which does not need to change when adding / removing sorting values โ€‹โ€‹of the sort. This will touch upon your second problem.

I can't give you a better implementation or set of design patterns because I don't know everything you do about the system being built, but I hope my thoughts here help.

+3


source


as M Platvoet said:



import java.util.*;
enum Category {
    Hot(EnumSet.of(Sort.Rising)),New(EnumSet.of(Sort.ThisWeek,Sort.ThisYear));
    Category(EnumSet<Sort> legal) {
        this.legal.addAll(legal);
    }
    boolean isLegal(Sort sort) {
        return legal.contains(sort);
    }
    private final EnumSet<Sort> legal=EnumSet.noneOf(Sort.class);
}
enum Sort {
    New,Rising,ThisWeek,ThisYear;
}
public class So9706550 {
        static boolean isValid(Category category,Sort sort) {
            return category.isLegal(sort);
    }
    public static void main(String[] args) {
        System.out.println(isValid(Category.Hot,Sort.Rising));
        System.out.println(isValid(Category.Hot,Sort.ThisWeek));
    }
}

      

+2


source


Just move the sort order check to the category enum. For him to readcategory.isValidSort(sort);

+1


source


For your first concern -

You can define a validator, which can be specific hashmap

, whose key will be category and sort.

you can pre-populate this map with valid combinations [you can think of a hardcoded / config file / periodic update, etc.).

In yours, validateCategorySortCombo

can you check if the hashmap actually contains the key? If so, it's good to go.

-

Map<Compositekey<Sort,Category>,Boolean> validOptions = new hashMap..

void validateCategorySortCombo(category, sort){

  if(validOptions.containskey(category,sort)){
     //good to go
  }
}

      

0


source


I noticed that you are not only validating the original data, but also generating a URL string from it. This might be a little over-the-top, but it looks like the classic case of Abstract Factory . You can have abstract families of categories and concrete implementations of SortedCategories. Another benefit is that you can explicitly throw an exception in the HotRaisedFactory as an unacceptable combination of this category and Sort.

0


source







All Articles