Java Learner

          基礎(chǔ)的重要性
          posts - 1, comments - 0, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          2007年9月28日

           

          Filter collections

          A simple generic mechanism for filtering collections

          Track: http://www.javaworld.com/javaworld/jw-10-2004/jw-1018-filter.html
          Often, you must iterate through a collection of objects and filter them based on a number of criteria. The JDK supplies a useful mechanism for sorting collections, namely the Comparator interface. However, the JDK lacks a mechanism for filtering collections.

          This article describes a simple mechanism consisting of only one class and one interface that allows you to filter collections quickly and neatly. When searching a collection, the described mechanism offers the same functionality as a SQL SELECT statement. Its underlying concept is its separation of responsibilities between iterating through the collection and filtering the objects in the collection.

          The approach presented here has the following benefits:

          1. Reuse of a central filtering component produces cleaner code
          2. Reuse of common filtering components generates less error-prone code
          3. Separating the iteration logic from the filtering logic allows you to add or remove filters at will without affecting any other code
          4. Possible performance gains with large collections and multiple criteria


          The problem

          Imagine a search mask where a user can choose among numerous different criteria to search for cars. Approaching this task simply, the developer must iterate through the collection multiple times. In each iteration, he must execute certain logic on each object in the collection to decide whether it fits the criteria. Usually, the result of this process is messy code that is both hard to read and maintain.

          The solution

          We define a class called CollectionFilter and an interface called FilterCriteria.

          FilterCriteria defines only one method: public boolean passes(Object o). In this method, an object in the collection must pass a certain test. If it passes the test, the method returns true, otherwise, false.

          CollectionFilter now takes any number of FilterCriteria as input. You then call the public void filter(Collection) method, which applies all FilterCriteria to the supplied collection and removes any object in the collection that doesn't pass all FilterCriteria.

          The CollectionFilter class also defines a public Collection filterCopy(Collection) method, which completes the same task as the filter(Collection) method, but on a copy of the original filter.

          That's it!

          As you may have noticed, this solution borrows some ideas from the Chain of Responsibility design pattern and applies them to a collection.

          The following class diagram illustrates the classes and interfaces and how they relate to each other.

          Class diagram. Click on thumbnail to view full-sized image.

          Simple example

          Let's look at an example: Class Car has three attributes: String color, double maxSpeed, boolean fourWheelDrive.

          Your application allows searching for cars based on these criteria. The user can enter the color she prefers. She can also provide the maximum speed she wants the car to have and also whether the car should support four-wheel drive.

          We now create three filter classes, one for each criteria the user can choose.

          1. Write the FilterCriteria implementations:

            class ColorFilterCriteria implements FilterCriteria{
                private String color;
                public boolean passes(Object o){
                return ((Car)o).getColor().equals(color);
                }
                }
                class MaxSpeedFilterCriteria implements FilterCriteria{
                private int maxSpeed;
                public boolean passes(Object o){
                return ((Car)o).getMaxSpeed() >= maxSpeed;
                }
                }
                class FourWheelDriveFilterCriteria implements FilterCriteria{
                private boolean fourWheelDriveRequired;
                private boolean fourWheelDriveAllowed;
                public boolean passes(Object o){
                return fourWheelDriveRequired?((Car)o).isFourWheelDrive():fourWheelDriveAllowed?true:!
                ((Car)o).isFourWheelDrive();
                }
                }
                
          2. Then add these FilterCriteria to a CollectionFilter:

            CollectionFilter collectionFilter = new CollectionFilter();
                filter.addFilterCriteria(new ColorFilterCriteria(color));
                filter.addFilterCriteria(new MaxSpeedFilterCriteria(maxSpeed));
                filter.addFilterCriteria(new FourWheelDriveFilterCriteria(fourWheelDriveRequired, fourWheelDriveAllowed));
                
          3. Now filter:

            collectionFilter.filter(carCollection);
                


          Technicalities

          As you may have realized, similar to the compare(Object o1, Object o2) method in the Comparator interface, the passes(Object o) method in the FilterCriteria interface takes an object of type Object as input. This means you must cast the object to the type you want to work with and ensure your collection only contains an object of that type. If this is not certain, you can use instanceof to test whether the specific object is of that type.

          Sometimes, you might prefer not to define a separate class for each FilterCriteria. The use of an anonymous inner class suggests itself in such cases.

          To keep the solution simple, I refrained from adding OR functionality to this filter. In other words, every time you add a FilterCriteria to your CollectionFilter, this can be compared to an AND in a SQL statement, since you're adding another condition. However, you can easily add OR-like functionality within one FilterCriteria. For example:

          class EitherOrColorFilterCriteria implements FilterCriteria{
          private String color1;
          private String color2;
          public boolean passes(Object o){
          return ((Car)o).getColor().equals(color1) || ((Car)o).getColor().equals(color2);
          }
          }
          

           

          posted @ 2007-09-28 18:02 Chris Huang 閱讀(173) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 邹平县| 台中市| 马鞍山市| 诸暨市| 耒阳市| 中西区| 平定县| 蕉岭县| 浙江省| 玉龙| 驻马店市| 九龙城区| 青冈县| 蕉岭县| 双流县| 柯坪县| 五家渠市| 新泰市| 扶沟县| 绍兴县| 扎兰屯市| 通榆县| 泗阳县| 康乐县| 华亭县| 贞丰县| 长宁县| 诸暨市| 松江区| 华宁县| 永安市| 万宁市| 江西省| 南溪县| 盘锦市| 瑞金市| 岐山县| 华亭县| 乐亭县| 濮阳县| 开远市|