策略模式示例代码
Strategy Design Pattern: is a type of behavioral design pattern that encapsulates a “family” of algorithms and selects one from the pool for use during runtime. The algorithms are interchangeable, meaning that they are substitutable for each other.
小号 战略研究设计模式:是一类封装了一个算法和选择一个从池中运行时使用的“家庭”行为的设计模式。 这些算法是可互换的,这意味着它们可以相互替代。
Check out the source code of the app to make it easier for you to follow up on the tutorial.
签出应用程序的源代码 ,使您可以更轻松地继续学习本教程。
问题: (Problem:)
In our movie app. The app fiches a list of top rated movies and TV shows from an API. The app also contains a filter options.We have 3 types of filters (genre, year, and rate).
在我们的电影应用中。 该应用程序通过API查找收视率最高的电影和电视节目的列表。 该应用程序还包含一个过滤器选项。我们提供3种类型的过滤器(类型,年份和费率)。
We fetch a list of movies from the server and applying each filter via a checkbox for each one. The problem here is that we need to apply each filter without affecting the previous one, e.g. If we choose genre filter and then we choose the year filter, I need the genre list to be updated and applying the year filter on it. Also, if we remove the year filter, we need the genre-filtered list to be shown (not the original one).
我们从服务器获取电影列表,并通过一个复选框对每个滤镜应用每个滤镜。 这里的问题是,我们需要应用每个过滤器而不影响前一个过滤器,例如,如果选择流派过滤器 ,然后选择年份过滤器 ,则需要更新流派列表并在其上应用年份过滤器。 另外,如果删除年份过滤器,则需要显示经过类型过滤的列表(而不是原始列表)。
iMovie UI
iMovie用户界面
解: (Solution:)
Strategy design pattern will solve this problem smoothly and easily.
策略设计模式将轻松轻松地解决此问题。
实现方式: (Implementation:)
We have three variables for filtering:
我们有三个过滤变量:
year: Integer, genreId: Integer, rate: Double.
year:Integer , genreId:Integer , rate:Double 。
We need to create a generic class so we can use same methods for both Integer and Double. 我们需要创建一个通用类,以便我们可以对Integer和Double使用相同的方法。
public abstract class Filter {
T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Then, we need to crate an interface with only one method which is used to call the other methods. 然后,我们只需要使用一个用于调用其他方法的方法来创建接口。
public interface Filterable {ArrayList applyFilter(ArrayList arrayList);}
now, we need to implement a class for each filter, (they all have to extends the generic class and implements the interface). 现在,我们需要为每个过滤器实现一个类(它们都必须扩展通用类并实现接口) 。
public class GenreFilter extends Filter implements Filterable {
@Override
public ArrayList applyFilter(ArrayList arrayList) {
if (value == null) {
return arrayList;
} else {
ArrayList newArrayList = new ArrayList<>();
for (int i = 0; i < arrayList.size(); i++) {
int tmp = arrayList.get(i).getGenreID();
if (tmp == value)
newArrayList.add(arrayList.get(i));
}
return newArrayList;
}
}
}
public class RateFilter extends Filter implements Filterable {
@Override
public ArrayList applyFilter(ArrayList arrayList) {
if (value == null) {
return arrayList;
} else {
ArrayList newArrayList = new ArrayList<>();
for(int i = 0 ; i < arrayList.size(); i++){
double tmp = arrayList.get(i).getRate();
if( value <= tmp)
newArrayList.add(arrayList.get(i));
}
return newArrayList;
}
}
}
public class YearFilter extends Filter implements Filterable {
@Override
public ArrayList applyFilter(ArrayList arrayList) {
if (value == null) {
return arrayList;
} else {
ArrayList newArrayList = new ArrayList<>();
for(int i = 0 ; i < arrayList.size(); i++){
int tmp = arrayList.get(i).getYear();
if( value <= tmp)
newArrayList.add(arrayList.get(i));
}
return newArrayList;
}
}
}
Note: We have used Double not double because we can assign it with a null value (same goes for Integer).
注意:我们使用Double not double是因为我们可以为其分配一个空值(对于Integer也是一样 )。
The last Thing we need to implement is a class for managing all the filters. 我们需要实现的最后一件事是用于管理所有过滤器的类。
public class FilterManager {
public ArrayList applyFilters(ArrayList arrayList, Filterable ... filters){
ArrayList filteredList = new ArrayList<>(arrayList);
for (Filterable f: filters) {
filteredList = f.applyFilter(filteredList);
}
return filteredList;
}
}
As you can see, this class contains only one method called applyFilters() which is responsible for creating a new ArrayList and applying each filter on it.
如您所见,该类仅包含一个名为applyFilters()的方法,该方法负责创建一个新的ArrayList并在其上应用每个过滤器。
Note: The parameter Filterable … filters allow us to pass variables as much as we need as we will see in the next step.
注意:参数Filterable…过滤器使我们可以根据需要传递变量,正如我们将在下一步中看到的那样。
In the next steps, We are going to see how the Strategy pattern makes our life easier.
在接下来的步骤中,我们将看到“策略”模式如何使我们的生活更轻松。
Initialize 2 arrayLists. 初始化2个arrayLists。
ArrayList filteredList, originalList;
Fetch the data from the API and store it in originalList. 从API提取数据并将其存储在originalList中 。
operations.fetchTopRated(MediaType.MOVIE.getValue(), items -> { originalList = new ArrayList<>(items); mainAdapter = new MainAdapter(getActivity(), originalList); mainListView.setAdapter(mainAdapter);});
Use the classes we have implemented in the previous steps. 使用我们在先前步骤中实现的类。
RateFilter rateFilter = new RateFilter();
rateFilter.setValue(singletonModel.getRate());
YearFilter yearFilter = new YearFilter();
yearFilter.setValue(singletonModel.getYear());
GenreFilter genreFilter = new GenreFilter();
genreFilter.setValue(singletonModel.getGenreId());
filteredList = new FilterManager().applyFilters(originalList, genreFilter, rateFilter, yearFilter);
As you can see, we declared an object of each filter class and set its value to the one that the user has chosen.
如您所见,我们声明了每个过滤器类的一个对象,并将其值设置为用户选择的对象。
In the last line, we called the FilterManager class which is responsible for applying the suitable filter and assign the output to filteredList.
在最后一行,我们调用了FilterManager类,该类负责应用合适的过滤器并将输出分配给filteredList 。
Thanks for reading…
谢谢阅读…
翻译自: https://medium.com/android-dev-hacks/strategy-design-pattern-android-real-life-example-a055bb0353b3
策略模式示例代码