Consider the case where a class contains two collections. Is it possible to provide iterators over both collections in a way that callers can use to iterate over?
My simple example:
public class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
public Iterator<Beer> beerIterator() { return beers.iterator(); }
public Iterator<Wine> wineIterator() { return wines.iterator(); }
}
So far, so good. We can declare the methods that return the iterators, but the way I'm trying to do it, the caller can't use the iterator to, well, iterate.
void caller(Bar bar) {
for (Beer beer: bar.beerIterator()) { // <-- Compilation error: Can only iterate over an array or an instance of java.lang.Iterable
}
}
Any suggestions?
If the point in returning iterators is to protect your collections from changes while giving client ability to use foreach loops, then the most clear way will be to use Collections.unmodifiableSet wrapper. You can return it as Iterable interface to hide the implementation even further.
public static class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
public Iterable<Beer> beerIterable() { return Collections.unmodifiableSet(beers); }
public Iterable<Wine> wineIterable() { return Collections.unmodifiableSet(wines); }
}
public static void main(String[] args) {
for (Bar.Beer beer : new Bar().beerIterable()) {
}
}
This approach is better than one suggested by #Tim Biegeleisen, because it protects your collection from being changed from outside. When you return .iterator of your original collection, client is still able to modify original collection by calling remove() method. Wrapping in unmodifiableSet prevents that.
However, be aware that client still can modify returned instances of Beer and Wine during the iteration, if they are mutable. If you want to be fully protected from changes, you need to make deep defensive copies of your collections before returning them to client.
The trick is to define 2 inner classes inside Bar which return custom iterators for beer and wine:
public class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
private class Beers implements Iterable<Beer> {
#Override
public Iterator<Beer> iterator() {
return beers.iterator();
}
}
private class Wines implements Iterable<Wine> {
#Override
public Iterator<Wine> iterator() {
return wines.iterator();
}
}
public Beers beers() {
return new Beers();
}
public Wines wines() {
return new Wines();
}
}
You can use the custom iterators like this:
Bar bar = new Bar();
// add some beers and wines here
for (Beer beer : bar.beers()) {
System.out.println("Found another beer: " + beer);
}
for (Wine wine : bar.wines()) {
System.out.println("Found another wine: " + wine);
}
Related
According to the SOLID principle open and close principle says class is open for extension and closed for modification.
So I am allowed to add new logic based on new if-else conditions?
If I will not use conditionals so how will I identify based on which condition which action has to be applied
public interface TemplateClassification {
QuesObj processTemplate(RawPart rawPart);
}
public class Template1 implements TemplateClassification{
#Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 1"+rawPart.getHead(),"Hi I am footer 1"+rawPart.getFoot());
}
}
public class Template2 implements TemplateClassification{
#Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 2"+rawPart.getHead(),"Hi I am footer "+rawPart.getFoot());
}
}
public class TemplateInfo {
private TemplateClassification templateClassification;
public TemplateClassification getTemplateClassification() {
return templateClassification;
}
public void setTemplateClassification(TemplateClassification templateClassification) {
this.templateClassification = templateClassification;
}
}
public class TemplateProduct {
public QuesObj calculateTemplate(TemplateInfo templateInfo,RawPart rawPart){
QuesObj ques = templateInfo.getTemplateClassification().processTemplate(rawPart);
return ques;
}
}
#RestController
class Pg {
#Autowired
TemplateInfo templateInfo;
#Autowired
TemplateProduct templateProduct;
public doProcessing(RawPart rawPart){
QuesObj ques = null;
if(rawPart.getId() == 1){
Template1 temp = new Template1();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(rawPart.getId() == 2){
Template2 temp = new Template2();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(tempId == 3){
// coming soon
}
}
}
How can i eliminte the if else condition so that it can follow open-close principle
To implement the "O" in SOLID, you can follow the below, which includes the "S" as well.
We are going to use polymorphism and inheritance.
Step 1 :
Create an interface that will sit in front of the classes that will be responsible in creating the QuesObj. We are going to need this, because down the line the code could receive a creator (child class) when id is 1,2 or 3.
It is important to note that QuesObj was identified because that is being returned on your original if statements and this is the reason we are allowed to continue with this approach.
public interface QuesObjCreator {
QuesObj calculate(RawPart rawPart);
}
Step 2:
Create individual class that creates the QuesObj in different ways in The only role of that class is to create the object.
public class QuesObjCreatorFor1 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
#Override
public QuesObj calculate(RawPart rawPart) {
Template1 temp = new Template1();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
public class QuesObjCreatorFor2 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
#Override
public QuesObj calculate(RawPart rawPart) {
Template2 temp = new Template2();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
Step 3:
Create a factory to return a QuesObjCreator. The factory will be returned to your main code/service.
public class QuesObjectCreatorFactory {
private static final Map<Integer,QuesObjCreator> quesObjCreatorMap = new HashMap<>();
public QuesObjectCreatorFactory() {
quesObjCreatorMap.put(1,new QuesObjCreatorFor1());
quesObjCreatorMap.put(2,new QuesObjCreatorFor2());
}
public static QuesObjCreator getQuesObjCreator(final int number) {
final QuesObjCreator quesObjCreator = quesObjCreatorMap.get(number);
if(quesObjCreator == null) {
throw new IllegalArgumentException("QuesObj for "+number+" does not exist");
}
return quesObjCreator;
}
}
Step 4:
Use Factory to create the QuesObj
public class Pg {
public void doProcessing(RawPart rawPart){
final QuesObjCreator quesObjCreator = QuesObjectCreatorFactory.getQuesObjCreator(rawPart.getId());
QuesObj ques = quesObjCreator.calculate(rawPart);
}
}
Collectively we achieved the Single responsibility across all classes and are decoupled.
It is easy to maintain cause now you can add more options to create QuesObj and none of the code would change, thus achieving open for extensibility/closed for modification.
It all boils down to the Factory and Map that has the creators. The map has to be populated with all the creator instances. With Spring this can be very easy, as Spring can scan your project, find beans of a specific type, give you a List and then you can convert it to a map.
Your case has nothing to do with SOLID. According to open-closed principle, you cannot allow modification to your class IN RUNTIME that can break its behavior.
In your case I suggest the following:
Add getId() method to your TemplateClassification interface.
Make each TemplateClassification implementation a bean
Add bean that will form the map of templates for you
#Bean
public Map<Integer, TemplateClassification> templates(List<TemplateClassification> templates) {
return algorithms.stream()
.collect(Collectors.toMap(TemplateClassification::getId, Function.identity()));
}
Autowire Map<Integter, TemplateClassification> templates to your controller and find the required template by id.
I've tried to do some stuff with generics already but it seems I cannot personally find any simple solution. Still I think it'd be a sin to leave these 3 similar methods alone as they are.
public List<PassengerPlane> getPassengerPlanes() {
List<PassengerPlane> passengerPlanes = new ArrayList<>();
for (Plane plane : planes) {
if (plane instanceof PassengerPlane) {
passengerPlanes.add((PassengerPlane) plane);
}
}
return passengerPlanes;
}
public List<MilitaryPlane> getMilitaryPlanes() {
List<MilitaryPlane> militaryPlanes = new ArrayList<>();
for (Plane plane : planes) {
if (plane instanceof MilitaryPlane) {
militaryPlanes.add((MilitaryPlane) plane);
}
}
return militaryPlanes;
}
public List<ExperimentalPlane> getExperimentalPlanes() {
List<ExperimentalPlane> experimentalPlanes = new ArrayList<>();
for (Plane plane : planes) {
if (plane instanceof ExperimentalPlane) {
experimentalPlanes.add((ExperimentalPlane) plane);
}
}
return experimentalPlanes;
}
What do you need is generic method, but the problem is that instanceof cannot check against type parameter (it is in fact erased during compilation), it requires actual class reference. So, you may provide this to the method explicitly:
public <T extends Plane> List<T> getPlanes(Class<T> claz) {
List<T> result = new ArrayList<>();
for (Plane plane : planes) {
if (claz.isInstance(plane)) {
result.add(claz.cast(plane));
}
}
return result;
}
Note how instanceof and explicit cast changed to calls to .isInstance() and .cast()
Use it like
getPlanes(PassengerPlane.class)
You can make things a bit shorter with Streams, but I'm not sure there's a way to get around using instanceof here:
public List<PassengerPlane> getPassengerPlanes() {
return planes.stream().filter(t -> t instanceof PassengerPlane)
.map(t -> (PassengerPlane) t).collect(Collectors.toList());
}
public List<MilitaryPlane> getMilitaryPlanes() {
return planes.stream().filter(t -> t instanceof MilitaryPlane)
.map(t -> (MilitaryPlane) t).collect(Collectors.toList());
}
public List<ExperimentalPlane> getExperimentalPlanes() {
return planes.stream().filter(t -> t instanceof ExperimentalPlane)
.map(t -> (ExperimentalPlane) t).collect(Collectors.toList());
}
Here's how I would approach the problem using generics:
public <T> List<T> getTPlanes(Class<T> clazz) { //declare the method to take a type generic
List<T> tPlanes = new ArrayList<>(); //initialize an ArrayList of that type
planes.stream() //stream the planes list
.filter(clazz::isInstance) //filter it down to only planes of the type that we want
.forEach((p) -> tPlanes.add((T) p)); //add each plane left in the stream to our new ArrayList, and cast it to the type generic
return tPlanes; //return the ArrayList we just created and populated
}
You do need to do a cast somewhere: Here is a solution with a single method that takes the subtype.
import java.util.*;
import java.util.stream.*;
public class Example {
public static class Plane { }
public static class PassengerPlane extends Plane { }
public static class MilitaryPlane extends Plane { }
public static class ExperimentalPlane extends Plane { }
private static List<Plane> planes =
List.of(new PassengerPlane(),
new MilitaryPlane(),
new ExperimentalPlane());
public static <T extends Plane> List<T> getPlanesOfType(Class<T> type, List<Plane> planes) {
List<T> list =
planes.stream()
.filter(t -> type.isAssignableFrom(t.getClass()))
.map(t -> type.cast(t))
.collect(Collectors.toList());
return list;
}
public static void main(String[] args) throws Exception {
System.out.println(getPlanesOfType(PassengerPlane.class, planes));
System.out.println(getPlanesOfType(MilitaryPlane.class, planes));
System.out.println(getPlanesOfType(ExperimentalPlane.class, planes));
System.out.println(getPlanesOfType(Plane.class, planes));
}
}
[Example$PassengerPlane#7b227d8d]
[Example$MilitaryPlane#7219ec67]
[Example$ExperimentalPlane#45018215]
[Example$PassengerPlane#7b227d8d, Example$MilitaryPlane#7219ec67, Example$ExperimentalPlane#45018215]
You could either use the single method to replace all three or use it to implement.
If your problem is really so short, probably it won't be worthy the effort. However, this is a typical problem for Visitor Pattern (especially if your duplicate code is larger).
Step 1
Create a Visitor interface to visit each type of Plane:
interface Visitor {
void visit(MilitaryPlane militaryPlane);
void visit(ExperimentalPlane experimentalPlane);
void visit(PassengerPlane passengerPlane);
}
... and implement it in a way that starts with a List<Plane> that can be enriched by each of the .visit():
class PlaneVisitor implements Visitor {
private final List<Plane> planes;
PlaneVisitor(List<Plane> planes) {
this.planes = requireNonNull(planes);
}
#Override
public void visit(MilitaryPlane militaryPlane) {
planes.add(militaryPlane);
}
#Override
public void visit(ExperimentalPlane experimentalPlane) {
planes.add(experimentalPlane);
}
#Override
public void visit(PassengerPlane passengerPlane) {
planes.add(passengerPlane);
}
public List<Plane> getPlanes() {
return planes;
}
}
Step 2 - Enable visitors in your classes
Add an abstract method in your base class Plane to accept the visitor:
public abstract class Plane {
//...
abstract void accept(Visitor visitor);
//...
}
Then implement this method in each sub-class to let the Visitor instance visit itself (this). Example for PassengerPlane (same logic for all the other classes):
public class PassengerPlane extends Plane {
//...
#Override
void accept(Visitor visitor) {
visitor.visit(this);
}
//...
}
Step 3 - Adapt your function
Your function can now loop through the list of planes not caring about the type. It will be resolved by the visitor:
public List<Plane> getPlanes() {
PlaneVisitor planeVisitor = new PlaneVisitor(new ArrayList<>());
for (Plane plane : planes) {
plane.accept(planeVisitor);
}
return planeVisitor.getPlanes();
}
Note that you need to add a bit of methods / interfaces to do this. Since your code is very small, you can imagine to leave it like it is even if it's not very "elegant". However, the above example can be of inspiration if your code is actually supposed to do more than what you're showing us.
It can be done in this way by introduced a method that do common part:
private static <T> List<T> createFilteredList(List<Plane> inList, Class<T> clazz) {
List<T> outList = new ArrayList<>();
for (Plane value : inList) {
if (clazz.isInstance(value)) {
outList.add(clazz.cast(value));
}
}
return outList;
}
Then it can be used like this:
public List<PassengerPlane> getPassengerPlanes() {
return createFilteredList(planes, PassengerPlane.class);
}
public List<MilitaryPlane> getPassengerPlanes() {
return createFilteredList(planes, MilitaryPlane.class);
}
public List<ExperimentalPlane> getPassengerPlanes() {
return createFilteredList(planes, ExperimentalPlane.class);
}
So, you have an iterable of Plane as an input.
A Plane can be PassengerPlane, MilitaryPlane or ExperimentalPlane.
What you are trying to do is to filter a collection of planes by a predicate. A predicate is a function that takes a Plane and answers true or false. A filter uses a predicate to figure out whether to include a given item into the result or to skip.
If you are using Java 8 or later version, you can use the Streams API.
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
Produce a stream from the planes iterable.
Apply filter to it (intermediate operation).
Collect the results to list.
Using Stream API you can convert the methods above into one-liners. Like this:
planes.stream().filter(plane -> plane instanceof MilitaryPlane).collect(toList());
Then, probably, you won't need a separate neat method for it.
But if you want some reusable piece of code, then you have to figure out what is the parameter here. In the code above it is a specific plane implementation:
public List<Plane> filterPlanes(Iterable<Plane> planes, Class<? extends Plane> planeImplementation)
So, you can build a predicate with this parameter:
plane -> planeImplementation.isInstance(plane)
If you have a Plane supertype, you can make the subclasses inherit the getPlanes() method. this.getClass will extract only the planes of the subclass calling the method from the list. This way, you don't have to pass a class to the method, as it can be derived from the subclass that is calling it.
public abstract class Plane {
public Plane(){}
public List<Plane> getPlanes() {
List<Plane> result = new ArrayList<>();
for (Plane plane : planes) {
if (this.getClass().isInstance(plane)) {
result.add(this.getClass().cast(plane));
}
}
return result;
}
}
class PassengerPlane extends Plane {
}
class MilitaryPlane extends Plane {
}
class ExperimentalPlane extends Plane {
}
public class PlaneList {
public String name;
public static ArrayList<Plane> planes = new ArrayList<>();
public PlaneList(){
planes.add(new MilitaryPlane());
planes.add(new MilitaryPlane());
planes.add(new MilitaryPlane());
planes.add(new PassengerPlane());
planes.add(new PassengerPlane());
planes.add(new ExperimentalPlane());
}
}
I tested it like so:
public class Main {
public static void main(String[] args) {
PlaneList list = new PlaneList();
Plane plane = new PassengerPlane();
for(Plane p : plane.getPlanes()){
System.out.println(p.toString());
}
}
}
output:
com.company.PassengerPlane#7dc36524
com.company.PassengerPlane#35bbe5e8
I have some helper classes for testing with the following structure:
public class EntitiesForTest {
public static Entity firstEntity() {
return new Entity(/*some dummy data*/)
}
public static Entity secondEntity() {...}
...
public static Entity nthEntity() {...}
public static List<Entity> allEntities() {???}
}
The purpose of this classes is to have some objects to test the upper layers of my system, like having some JSON data to test a REST service. This technique is not mine but from an online course I'm taking and is pretty cool.
I'd like to know if there is a way to construct a List<Entity> based on the static inherited methods of the class and with the Collection framework. I can do Arrays.asList(/*call the methods one by one comma-separated*/) but there must be a smarter, functional and reusable way of doing this.
Thanks in advance for your answers.
"Modern" Way
public static List<Entity> getEntities() {
return Arrays.stream(Foo.class.getMethods()).
filter(method -> method.getReturnType() == Entity.class &&
Modifier.isStatic(method.getModifiers())).
map(method -> {
try {
return (Entity)method.invoke(null);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e); // exceptions in streams... lol
}
}).
collect(Collectors.toList());
}
I wish I knew a way to avoid the cast, but that's not immediately clear to me.
Here is the samele code for invoking specified methods of EntitiesForTest class and collect the return objects:
public static List<Entity> allEntities() {
ArrayList<Entity> list = new ArrayList<Entity>();
Method[] ma = EntitiesForTest.class.getMethods();
Object[] emptyObject = new Object[0];
for (int i = 0; i < ma.length; i++) {
if (ma[i].getReturnType().equals(Entity.class) &&
ma[i].getParameterTypes().length == 0 &&
Modifier.isStatic(ma[i].getModifiers())) {
try {
Entity e = (Entity)(ma[i].invoke(null, emptyObject));
list.add(e);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return list;
}
This answer makes several assumptions:
You don't need the individual methods (firstEntity, secondEntity, etc.)
The entities only hold data and are not expensive to create and keep around
You don't need to modify them, which means you wouldn't call your methods multiple times.
These might not hold, because we have no definition of Entity or how it's used.
All in all, I'm just removing your methods.
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class EntitiesForTest {
private static final List<Entity> entities = Arrays.asList(
new Entity(),
new Entity(),
new Entity()
);
public static Entity allEntities(int n) {
return entities.get(n);
}
public static List<Entity> allEntities() {
return Collections.unmodifiableList(entities);
}
}
Maybe using a functional way (in java 8 ) ?
public class Entities {
static class Entity{
private String x;
Entity( String x){
this.x = x;
}
public String getX(){
return x;
}
}
public static Entity firstEntity() {
return new Entity("first Entity");
}
public static Entity secondEntity() {
return new Entity("second Entity");
}
public static Entity nthEntity() {
return new Entity("nth Entity");}
#FunctionalInterface interface GetEntity{
public Entity getEntity();
}
public static List<GetEntity> allEntities =
Arrays.asList(Entities::firstEntity,
Entities::secondEntity,
Entities::nthEntity);
public static void main(String ...p){
allEntities
.stream()
.forEach(x->{System.out.println(x.getEntity().getX());});
}
}
let's imagine the following situation: I want to design a bidding application (like ebay) with the composite design pattern
I create an abstract superclass like "BidComponent" (which has getName()) and two subclasses "Article" and "Category".
Category has a List which can contain other BidComponents, Article does not implement a List but a getPrice() method.
If I want to iterate through this structure and I want to print out the Category-Article-Structure I need instanceof:
if(element instanceof Article){
Article article = (Article)element;
System.out.println(article.getName() + ":" + article.getPrice());
}else{
Category category = (Category)element;
System.out.println(category.getName());
}
This seems pretty wrong to me. Is there a better way to realise this (So without always checking the type via instanceof)? I ask this question because I read several times that using instanceof is bad design...
//Edit to mention my problem with Visitors:
Ok. But let's imagine I want to search the highest bid to all products. So I have
public class HighestBidVisitor implements BidComponentVisitor{
private double highestBid = 0d;
public HighestBidVisitor(Category category){
visitCategory(category);
}
#Override
public void visitCategory(Category category){
Iterator<BidComponent> elementsIterator = category.iterator();
while(elementsIterator.hasNext()){
BidComponent bidComponent = elementsIterator.next();
//Now I have again the problem: I have to check if a component in the Categorylist is an article or a category
if(bidComponent instanceof Article) visitArticle((Article)bidComponent);
else visitCategory((Category)bidComponent);
}
}
#Override
public void visitArticle(Article article){
if(article.getPrice() > highestBid) highestBid = article.getPrice();
}
}
But now I have the same problem again (See comment in visitCategory). Or am I doing this wrong?
You want to use the visitor pattern.
public interface BidComponentVisitor {
void visitArticle(Article article);
void visitCategory(Category category);
}
Then your BidComponent class would have a visit method:
public abstract void visitChildren(BidComponentVisitor visitor);
The Composite and Visitor patterns often work together.
Edit: The key to avoiding instanceof when using the vistor pattern is how you implement the visitChildren method. In Category you would implement it like this:
#Override
public void visitChildren(BidComponentVisitor visitor) {
vistor.visitCategory(this);
for (BidComponent child : children) {
child.visitChidren(visitor);
}
}
Since Article has no children, it's implementation is simpler:
#Override
public void visitChildren(BidComponentVisitor visitor) {
vistor.visitArticle(this);
}
They key is each concrete class in the composite pattern knows it's own type, so it can call the specific visitor method that has a parameter with it's specific type.
One variation is to have enter and exit methods in the visitor for any class with children:
public interface BidComponentVisitor {
void visitArticle(Article article);
void enterCategory(Category category);
void exitCategory(Category category);
}
With the above interface, Category.visitChildren() would look like this:
#Override
public void visitChildren(BidComponentVisitor visitor) {
vistor.enterCategory(this);
for (BidComponent child : children) {
child.visitChidren(visitor);
}
vistor.exitCategory(this);
}
To print the tree, you could do something like this:
public class PrintingVisitor implements BidComponentVisitor {
private int depth = 0;
private void printIndent() {
for (int i = 0; i < depth; i++) {
System.out.print(" ");
}
}
public void visitArticle(Article article) {
printIndent();
System.out.println(article.toString());
}
public void enterCategory(Category category);
printIndent();
System.out.println(category.toString());
depth++;
}
public void exitCategory(Category category) {
depth--;
}
}
The disadvantage of the visitor patter is your visitor class needs to either hardcode every possible subclass, or have a generic visitOther() method.
You are doing the visitor implementation wrong. The different Components handle their own dispatching of elements. They know what type they are so you don't need to do any instanceof checks.
public interface Visitor{
void visit(Article a);
void visit(Category c);
}
abstract class BidComponent{
...
abstract void accept(Visitor v);
}
public class Category{
....
public void accept(Visitor v){
v.visit(this); // visit Category
for(Article a : getArticles()){
v.visit(a); //visit each article
}
}
}
Then a visitor to find the highest bid
public class HigestBidVisitor implements Visitor{
private final double highest;
void visit(Category c){
//no-op don't care
//or we could track which Category we have visited last
//to keep track of highest bid per category etc
}
void visit(Article a){
highest= Math.max(highest, a.getPrice());
}
}
Then to search all:
HigestBidVisitor visitor = new HighestBidVisitor();
BidComponent root = ...
root.accept(visitor);
double highest = visitor.getHighestPrice();
I can't think of any clean solution right now. You might have to update your implementation to either store Article and Category instances separately.
With your current implementation where a List<BidComponent> needs to be traversed and each element needs to be processed based on it's type, this approach can be a bit better:
abstract class BidComponent {
public abstract String process();
}
class Category extends BidComponent {
#Override
public String process() {
return getName();
}
}
class Article extends BidComponent {
#Override
public String process() {
return getName() + " " + getPrice();
}
}
List<BidComponent> list = ..;
for (BidComponent c : list) {
System.out.println(c.process());
}
Another way to decouple the processing logic from the classes/objects is:
Map<Class<?>, Function<BidComponent, String>> processors = new HashMap<>();
processors.put(Category.class, Category::getName());
processors.put(Article.class, a -> a.getName() + " " + a.getPrice());
List<BidComponent> list = ..;
for (BidComponent c : list) {
System.out.println(processors.get(c.getClass()).apply(c));
}
Note that this uses Java 8 lambdas but the same can be implemented with Java 7 or lower by using your own interface (similar to Function) or the ones provided by Guava or Apache Commons.
I want to detect when adding some items to the array list or when removing some item from it. Actually I have some code like below:
public class myClass {
MyCustomArrayList<MyObject> al;
public void method1() {
al.add(myObject);
// Do other works
al.remove(myObject)
// Do other works
}
private void DoByEachAdd() {
//I want array list call this method by adding each item to it.
// It should be in this class because it is doing some works
// related to this class. for example changing some private variables
}
private void DoByEachRemove() {
// I want array list call this method by adding each item to it.
// It should be in this class too.
}
}
I know that array list has not the ability for having listener or some kind of notifications or events and if I want to detect add should have a custom array list. something like below class:
class MyArrayList<T> {
private ArrayList<T> list;
public MyList(){
list = new ArrayList<>();
...
}
public void add(T t) {
list.add(t) {
//do other things you want to do when items are added
}
public T remove(T t) {
list.remove(t);
//do other things you want to do when items are removed
}
(I get it from here)
So the question is that: how can I inform the object of MyArrayList (al) that call DoByEachAdd and DoByEachRemove methods when the remove and add method fired. Does some body have any ideas?
First, follow naming convention. Second, the three class names you used for the same class, MyList, MyArrayList and MyCustomArrayList will confuse people. As for your question, you would have to have an instance field inside MyArrayList of type myClass (unless you want to refactor DoByEachAdd and DoByEachRemove to be static). This can be done by adding it as a constructor parameter, e.g.
// inside MyArrayList
private ArrayList<T> list;
private final myClass instance;
public MyArrayList(myClass instance) { // <-- NOT MyList
list = new ArrayList();
this.myClass = myClass;
}
Also, I question your approach. Other classes with instances of MyArrayList can only use the add and remove methods of ArrayList. If you want to save a lot of bother and have all methods visible, either declare list as public final or make MyArrayList a subclass of ArrayList, e.g.
public class MyArrayList<T> extends ArrayList<T> {
private final myClass instance;
public MyArrayList(myClass instance) { // <-- NOT MyList
list = new ArrayList();
this.myClass = myClass;
}
#Override
public boolean add(T t) {
boolean returnThis = super.add(t);
// do some stuff
instance.DoByEachAdd();
return returnThis;
}
#Override
public boolean remove(T t) {
boolean returnThis = super.remove(t);
// do some stuff
instance.DoByEachRemove();
return returnThis;
}
}
If you insist on being able to return a T from remove, declare another method:
public T removeT(T t) {
remove(t);
// do some stuff
return someT;
}
you need to give access to your myClass to MyArrayList
class MyArrayList<T> {
private ArrayList<T> list;
private myClass theClass;
public MyList(myClass theClass){
list = new ArrayList<>();
this.theClass = theClass;
...
}
public void add(T t) {
list.add(t) {
//do other things you want to do when items are added
theClass.DoByEachAdd();
}
public T remove(T t) {
list.remove(t);
//do other things you want to do when items are removed
theClass.DoByEachRemove
}
and in your myClass give the object to your list
public class myClass {
MyCustomArrayList<MyObject> al;
public myClass(){
al = new MyCustomArrayList<MyObject>(this);
}
public void method1() {
al.add(myObject);
// Do other works
al.remove(myObject)
// Do other works
}
public void DoByEachAdd() {
//I want array list call this method by adding each item to it.
// It should be in this class because it is doing some works
// related to this class. for example changing some private variables
}
public void DoByEachRemove() {
// I want array list call this method by adding each item to it.
// It should be in this class too.
}
}