Let’s say I am working with bicycles and I need to group them by different criterias.
class Bicycle { String brand { get; set; } Date purchaseDate { get; set; } } class GroupedBicycles { String groupingCriteria { get; set; } /* will contain all bikes with this criteria for example, if grouped by brand, all bikes in this list will have current brand */ List<Bicycle> bicycles { get; set; } } class BicyclesByBrand extends GroupedBicycles { } class BicyclesByPurchaseDate extends GroupedBicycles { Date groupingCriteria { get; set; } // will contain purchase date } List<BicyclesByBrand> groupBicyclesByBrand(List<Bicycle> bicycles) { List<BicyclesByBrand> result = new List<BicyclesByBrand>(); // Here is my own logic for grouping bicycles by criteria for (Bicycle bike : bicycles) { Boolean thisBikeIsGrouped = false; for (BicyclesByBrand bikesByBrand : result) { if (bikesByBrand.groupingCriteria == bike.brand) { // **MARK1 will explain below** bikesByBrand.bicycles.add(bike); thisBikeIsGrouped = true; break; } } if (!thisBikeIsGrouped) { BicyclesByBrand bikesByBrand = new BicyclesByBrand(); bikesByBrand.groupingCriteria = bike.brand; bikesByBrand.bikes = new List<Bicycle> { bike }; } } return result; }
the issue for me is that for grouping bikes by purchase date, I need to copy the same method and change only line marked as MARK1
Field needs to be changed from brand to purchaseDate.Is there a way in apex to create this method only once, but pass field for grouping as parameter? I believe this is possible in java by using reflection.
I expect this method to have following signature:
List<GroupedBicycles> groupBicyclesList<Bicycle> bicycles, String fieldCriteria)
I have already implemented displaying this data in visualforce, I have one apex:repeat that uses base class as var attribute, and in controller different implementations are assigned depending on grouping selected, so I am aiming to do minimal changes of data structure.
Answer
Not entirely sure I follow what you are aiming to do but this approach comes to mind…
I suggest you move the selection to a separate class that implements a Filter
interface:
public class Bikes {
public interface Filter {
Boolean accept(Bicycle b);
}
public static Bicycle[] filter(Bicycle[] bicycles, Filter filter) {
Bicycle[] results = new Bicycle[] {};
for (Bicycle b : bicycles) {
if (filter.accept(b)) results.add(b);
}
return results;
}
}
You can the write filters as required e.g.:
public class BrandFilter implements Bikes.Filter {
private String brand;
public BrandFilter(String brand) {
this.brand = brand;
}
public Boolean accept(Bicycle b) {
return b.brand == brand;
}
public override String toString() {
return 'Brand ' + brand;
}
}
or:
public class PurchaseDateFilter implements Bikes.Filter {
private Date purchaseDate;
public PurchaseDateFilter(Date purchaseDate) {
this.purchaseDate = purchaseDate;
}
public Boolean accept(Bicycle b) {
return b.purchaseDate == purchaseDate;
}
public override String toString() {
return 'Purchase Date ' + purchaseDate.format();
}
}
or if you are using sub-classing you can use instanceof
and casts as needed. Or you can write one filter class that accepts many parameters; the key point is to separate out the filtering from other logic.
So to find all bikes of a brand:
Bicycle[] input = ...
Bicycle[] output = Bikes.filter(input, new BrandFilter('Cinelli'));
You can also create and
and or
filters so combinations can be applied.
PS
If you want to keep your GroupedBicycles
class:
public class GroupedBicycles {
public String groupingCriteria { get; set; }
public List<Bicycle> bicycles { get; set; }
public GroupedBicycles(Bicycle[] allBicycles, Bicycles.Filter filter) {
groupingCriteria = filter.toString();
bicycles = Bikes.filter(allBicycles, filter);
}
}
public GroupedBicycles[] grouped {get; set;}
private void init() {
Bicycle[] allBicycles = ...
grouped = new GroupedBicycles[] {
new GroupedBicycles(allBicycles, new BrandFilter('Cinelli')),
new GroupedBicycles(allBicycles, new BrandFilter('Condor')),
new GroupedBicycles(allBicycles, new PorchaseDateFilter(Date.today())),
...
};
}
Attribution
Source : Link , Question Author : Vladyslav K , Answer Author : Keith C