Background
For my assignment I am required to model filters such as those in signal processing at a basic level. Filters can take inputs of any type and output a different type if that's how the filter is implemented. The most simple filter outputs the input. Other example filters are arithmetic mean, max, or min filters which returns the maximum input. Similar filters can only return the mean/max/min of the last N inputs. Some filters are reset-able and has a method "reset" which takes an input of the same type. So for example a max3 filter returns the maximum number of the three last inputs or since the last reset including the input that the reset method takes. The assignment goes in further detail describing other more complicated filters but I'm having trouble with abstraction at the most basic level.
Attempt
So my first attempt was to create an interface "Filter" which had one method "filter". This would be implemented by filters to suite their own needs. I created an abstract class "StorageFilter" which stored a list of inputs accessible with protected set/get methods. Then I extended that class to implement the reset function in another abstract class "ResetableFilter". So filters that can't reset would extend the first abstract filter and filters that can would reset the second. But my implementation didn't really work out since filters are a little more complicated than that. There are a few main types of filters that I can pin down. Filters that:
store one input such as max/min filters: just compare stored value with input and if it's the new max/min then set the stored value to the input. We'll call this type 1.
store a list of inputs such as max/min filters of last N: only stores the last N inputs so the filter method can iterate through the list and find the max/min. We'll call this type 2. (This could also implemented in another way storing two values, one representing the current max/min and its "age")
store a list of inputs and a list of outputs such as complicated scalar linear filters which uses equations uses both to calculate the new output. We'll call this type 3.
store none at all such simple filters like the first example or a filter that just returns double the input. We'll call this type 4
So there are many types of things that a filter can store but not all filters are reset-able.
Problem
My general question is how can I implement optional methods while maintaining abstraction? This type (filter) can have an optional method (reset) that its subtypes can have. I can't just have an empty method "reset" that does nothing but the filter is still able to call. What is the best way to implement an optional method such as in this case while maintaining abstraction?
Potential Solutions
Use #Optional: Using this annotation means that filters that don't use this method will throw an UnsupportedOperationException. This is an acceptable way of maintaining abstraction since Java's Collections uses it but it's not desirable since exceptions are involved.
Create a "Reset" interface and have each Filter that can reset implement it: This is also bad because it will almost double the types of Filters I have to think about. (i.e Type 1 filters, reset-able Type 1 filters, ..., and Type 4 filters. Since type 4 filters don't store anything they don't reset ever)
The book "Code Complete 2" describes a scenario modeling a Cat. Cats can scratch but some cats are declawed and therefore can't scratch. Creating different classes for things that a cat can or cannot do complicates it so that you'll end up with classes like a ScratchlessTailess...Cat. The solution the book offers is to create an inner class "Claws" that is contained within the Cat class or build a constructor that includes whether the cat scratches. From this I think an optimal solution would be to create an inner interface "ResetableContainer" which has the one method reset which can be implemented to fit the different types. It could hold whatever the filters need to store and the reset will be implemented depending on what was stored. The problem is still how can I implement it to avoid all this complication with the different possibilities of storage (a single input or a list of inputs)?
It looks like you are running into a conceptual design problem, in that you are expecting the user of the Filter to always know exactly what it can and can't do. But at the same time, you want filters to be able to do lots of different things... these two ideas can't entirely mesh.
What you can do is create these 'optional' methods to return a value on execution:
/**
* Resets the filter.
*
* #returns
* false if this operation is not supported by the filter
*/
public boolean reset() {
return false;
}
A much better method: Include include an additional method that must be overridden, a more common design pattern: see this question for an example. As stated there, it's also probably good to just have more than one interface.
This sounds like a school assignment, so you may be constrained in a way that you can't do this, but what I would do is keep it simple: a single interface:
public interface Filter<In, Out> {
public Out filter(In toFilter);
public void reset();
public boolean canReset();
}
And then probably an abstract base class to provide good default implementations for those methods that have them:
public abstract class BaseFilter<In, Out> implements Filter<In, Out> {
public void reset() {}
public boolean canReset() { return false; }
}
I wouldn't have even included canReset except for the possibility of filters which are sometimes resetable and sometimes not. If that's not a possibility you want to support then you can remove the canReset and just always call reset() whenever you would reset it if it were a resetable filter.
Related
I'm working my through an assignment and got stuck on step 5, would appreciate any help.
Carefully study the class structure in Products.java.
Design a generic container called GenericOrder that acts as a collection of an arbitrary number of objects in Products.java. Design a mechanism that gives each instance of the container a unique identifier. Implement as many methods as necessary. You must use Java generics features.
Design and implement a subclass of GenericOrder called ComputerOrder that takes an arbitrary number of different classes of ComputerPart objects, Peripheral objects, and Service objects. Implement as many methods as necessary.
Design and implement a subclass of GenericOrder called PartyTrayOrder that takes an arbitrary number of different classes of Cheese objects, Fruit objects, and Service objects. Implement as many methods as necessary.
Design and implement a class called OrderProcessor. You must implement at least the following methods:
accept; // this method accepts a GenericOrder or any of its subclass objects and stores it in any internal collection of OrderProcessor.
process; // this method sorts all accepted orders in the internal collection of GenericOrder into collections of ComputerPart, Peripheral, Cheese, Fruit, and Service. You must associate each object with the unique identifier. You may refer to the TwoTuple.java example in the text book.
dispatchXXX; // this method simulates the dispatch of the sorted collections. For example, the method dispatchComputerParts() should produce this output:
Motherboard name=Asus, price=$37.5, order number=123456
Motherboard – name=Asus, price=$37.5, order number=987654
RAM – name=Kingston, size=512, price=$25.0, order number=123456
Create a client class to test OrderProcessor. You will need to create a datagenerator for testing purpose. It is not mandatory but you may use a variation of Data Generator in TIJ pages 637 to 638.
Here is what I have for Q5
public abstract class OrderProcessor<T> {
private ArrayList<T> dataCollection = new ArrayList<T>();
public void accept(T item){
dataCollection.add(item);
}
public void process(){
Collections.sort(dataCollection);
}
public List getDataCollection(){
return dataCollection;
}
}
In its current state Collections.sort(dataCollection); doesn't compile because it does not accept T and if I change the ArrayList to String any function used from other subclasses won't work because they all T. Any help would be greatly appreciated.
thanks in advance.
EDIT: Since you want to partition your orders and not sort, you can use something like this:
dataCollection.stream().collect(
Collectors.groupingBy(order -> order.getIdentifier())
)
Here, this groups them by their identifiers and puts them into a Map. The order.getIdentifier() part is just a placeholder for whatever you want to use to divide them up. The return type will be Map<TypeOfIdentifier, T>.
For this to work, though, your T has to be of some specific type (T extends Product perhaps?) so you can get the identifier. Since I don't know the code for differentiating between different products, I can't put the exact code here.
The Javadoc for Collectors
This is why Collections.sort wasn't working for you, but you don't need Collections.sort anyways.
T must extend the Comparable interface, because obviously you can't sort objects of just any type. The Comparable interface has a compareTo method that lets you sort.
An alternative would be to write a custom Comparator that defines a single method: compare, which would take 2 objects of type T and return an int representing the order (in most cases it's basically the first argument minus the second argument). For this, you would need to use Collections.sort(dataCollection, customComparator).
You can define your comparator with a lambda expression, but I can't help you beyond that because I have no idea how you want to sort your objects.
This question already has answers here:
Class Object vs Hashmap
(3 answers)
Closed 3 years ago.
I have some piece of code that returns a min and max values from some input that it takes. I need to know what are the benefits of using a custom class that has a minimum and maximum field over using a map that has these two values?
//this is the class that holds the min and max values
public class MaxAndMinValues {
private double minimum;
private double maximum;
//rest of the class code omitted
}
//this is the map that holds the min and max values
Map<String, Double> minAndMaxValuesMap
The most apparent answer would be Object Oriented Programming aspects like the possibility to data with functionality, and the possibility to derive that class.
But let's for the moment assume, that is not a major factor, and your example is so simplistic, that I wouldn't use a Map either. What I would use is the Pair class from Apache Commons: https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/tuple/Pair.html
(ImmutablePair):
https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/tuple/ImmutablePair.html
The Pair class is generic, and has two generic types, one for each field. You can basically define a Pair of something, and get type safety, IDE support, autocompletion, and the big benefit of knowing what is inside. Also a Pair features stuff that a Map can not. For example, a Pair is potentially Comparable. See also ImmutablePair, if you want to use it as key in another Map.
public Pair<Double, Double> foo(...) {
// ...
Pair<Double, Double> range = Pair.of(minimum, maximum);
return range;
}
The big advantage of this class is, that the type you return exposes the contained types. So if you need to, you could return different types from a single method execution (without using a map or complicated inner class).
e.g. Pair<String, Double> or Pair<String, List<Double>>...
In simple situation, you just need to store min and max value from user input, your custom class will be ok than using Map, the reason is: in Java, a Map object can be a HashMap, LinkedHashMap or and TreeMap. it get you a short time to bring your data into its structure and also when you get value from the object. So in simple case, as you just described, just need to use your custom class, morever, you can write some method in your class to process user input, what the Map could not process for you.
I would say to look from perspective of the usage of a programming language. Let it be any language, there will be multiple ways to achieve the result (easy/bad/complicated/performing ...). Considering an Object oriented language like java, this question points more on to the design side of your solution.
Think of accessibility.
The values in a Map is kind of public that , you can modify the contents as you like from any part of the code. If you had a condition that the min and max should be in the range [-100 ,100] & if some part of your code inserts a 200 into map - you have a bug. Ok we can cover it up with a validation , but how many instances of validations would you write? But an Object ? there is always the encapsulation possibilities.
Think of re-use
. If you had the same requirement in another place of code, you have to rewrite the map logic again(probably with all validations?) Doesn't look good right?
Think of extensibility
. If you wanted one more data like median or average -either you have to dirty the map with bad keys or create a new map. But a object is always easy to extend.
So it all relates to the design. If you think its a one time usage probably a map will do ( not a standard design any way. A map must contain one kind of data technically and functionally)
Last but not least, think of the code readability and cognitive complexity. it will be always better with objects with relevant responsibilities than unclear generic storage.
Hope I made some sense!
The benefit is simple : make your code clearer and more robust.
The MaxAndMinValues name and its class definition (two fields) conveys a min and a max value but overall it makes sure that will accept only these two things and its class API is self explanatory to know how to store/get values from it.
While Map<String, Double> minAndMaxValuesMap conveys also the idea that a min and a max value are stored in but it has also multiple drawbacks in terms of design :
we don't know how to retrieve values without looking how these were added.
About it, how to name the keys we we add entries in the map ? String type for key is too broad. For example "MIN", "min", "Minimum" will be accepted. An enum would solve this issue but not all.
we cannot ensure that the two values (min and max) were added in (while an arg constructor can do that)
we can add any other value in the map since that is a Map and not a fixed structure in terms of data.
Beyond the idea of a clearer code in general, I would add that if MaxAndMinValues was used only as a implementation detail inside a specific method or in a lambda, using a Map or even an array {15F, 20F} would be acceptable. But if these data are manipulated through methods, you have to do their meaning the clearest possible.
We used custom class over Hashmap to sort Map based on values part
Suppose I have a private ArrayList or a LinkedList inside a class, that I will never assign new reference to it, or in other words this will never happen:
myLinkedList = anotherLinkedList;
So that I won't need to use setMyLinkedList(anotherLinkedList).
But! I need to add elements to it, or remove elements from it.
Should I write a new kind of setter to only, do the task of adding instead of setting, like myLinkedList.add(someElement)?
Or it is OK to do this by using getter, without disobeying Encapsulation principal?
getMyLinkedList().add(someElement)
( + Suppose I am going to lose my mark if I disobey encapsulation :-")
I don't think it a particularly great practice to do something like:
myObj.getMyList().add(x);
since you are exposing a private class variable in a non read only way, but that being said I do see it pretty frequently(I'm looking at you, auto generated classes). I would argue that instead of doing it that way, return an unmodifiable list and allow users of the class to add to the list via an explicit method:
public class MyClass{
private final List<String> myList = new ArrayList<String>();
public List<String> getList(){
return Collections.unmodifiableList(this.myList);
}
public void addToList(final String s){
this.myList.add(s);
}
}
EDIT After reviewing your comments, I wanted to add a bit about your setter idea:
I meant using that line of code inside a new kind of setter inside the class itself, like public void setter(someElement){this.myLinkedList.add(someElement);}
If I'm understanding you correctly, you are saying you want to expose a method that only adds to your list. Overall this is what I think you should be shooting for, and what many have outlined in the answers, however, labeling it as a setter is a bit misleading since you are not reassigning (setting) anything. That, and I strongly recommend returning a read only list from your getter method if possible.
I would suggest in this case it would be best to follow your Encapsulation principals and use a method for adding elements to the list. You have restricted access to your list by making it private so that other classes cannot directly access the datatype.
Let the class that stores your ArrayList have direct access to the list, but when other classes want to add to the list, use an add() method.
In general, you should not assume that the list being returned by the getter is the original one. It could be decorated or proxied for example.
If you want to prevent that a new list is set on the target object, you could define an add method on the target class instead.
As soon as you have a Collection of any kind, it is generally not a bad idea to add methods like add(), remove() to the interface of your class if it makes sense that clients can add or remove objects from your private list.
The reason why it is useful to have these extra methods implemented (it might seem like overkill, because after all those methods mostly just call the method on the Collection) is that you protect evil clients from doing things to your list you don't want them to do, because the interface of most Collections contain more than just the add() and remove() methods and mostly, you don't want clients to be messing around with things you can't control. Therefore the encapsulation principle is that important to your teacher.
Another plus: if at any time, you would decide that a certain condition must be met when an object is added to your list, this can easily be implemented in the method you already have. If you give a client access to the direct reference of your list, it is not easy at all to implement this kind of things (which are not rare).
Hope this helps
So you have a class containing a List field (it should be final, since you don't intend to assign to it), and you want to allow callers to add to the List, but not be able to replace it.
You could either provide a getter for the list:
public List<E> getMyList() {
return myList;
}
Or provide a method to add to that list:
public void addToMyList(E e) {
myList.add(e);
}
Both are valid design decisions, but which you use will depend on your use case. The first option gives callers direct access to the List, effectively making it public. This is useful when users will be modifying and working with the list repeatedly, but can be problematic as you can no longer trust the List is in any sort of reliable state (the caller could empty it, or reorder it, or even maliciously insert objects of a different type). So the first option should only be used when you intend to trust the caller.
The second option gives the caller less power, because they can only add one element at a time. If you want to provide additional features (insertion, add-all, etc.) you'll have to wrap each operation in turn. But it gives you more confidence, since you can be certain the List is only being modified in ways you approve of. This latter option also hides (encapsulates) the implementation detail that you're using a List at all, so if encapsulation is important for your use case, you want to go this way to avoid exposing your internal data structures, and only expose the behavior you want to grant to callers.
It depends on the application - both are acceptable. Take a good look at the class you're writing and decide if you want to allow users to directly access the contents of the list, or if you would prefer that they go through some intermediate process first.
For example, say you have a class ListEncrypter which holds your MyLinkedList list. The purpose of this class is to encrypt anything that is stored in MyLinkedList. In this case, you'd want to provide a custom add method in order to process the added item before placing it in the list, and if you want to access the element, you'd also process it:
public void add(Object element)
{
MyLinkedList.add(encrypt(element););
}
public Object get(int index)
{
return decrypt(MyLinkedList.get(index););
}
In this case, you clearly want to deny the user's access to the MyLinkedList variable, since the contents will be encrypted and they won't be able to do anything with it.
On the other hand, if you're not really doing any processing of the data (and you're sure you won't ever need to in the future), you can skip creating the specialized methods and just allow the user to directly access the list via the get method.
I have an interesting design problem that I will attempt to simplify in a toy problem below:
I wish to design a system for which the output will be student objects based on certain inputs and intermediary processing. The flow will be as follows: I have a list of classrooms as one type of input. To generate the output, the processing steps are:
Filter each classroom by students under the age of X (lets say 10)
Sort the filtered results by any permutation of this hierarchical order: height, weight, arm length
Return the top 8 students.
Another input can simply be a list of students I already have and want included as part of the result. For example: Input 1: List of 3 students, Input 2: List of 2 classrooms for which the processing steps above will run.
What would be the best way to design such a system with inputs being:
input type {student list|classroom list},
filter type {age|height|etc},
sort order{any ordering of height,weight,arm length},
returnNum{how many students to return}
The system should be flexible enough to accommodate more input types and more sort order entries {ie. sort students by shoe size}. What data structure can I use to model each part of this section (ie. what is the best way to represent the sort order criteria?) Is there any design pattern that would fit these needs? Any help with the architecture design would be greatly appreciated!
Well, what you're suggesting can be done easily with Java 8 streams, so I guess one pattern you could follow is that of a pipeline. You could also implement this using internal iterators:
List<Student> found = Stream.of(student1, student2, student3, ..., studentn)
.filter(s -> s.getAge() > 100)
.sorted(Comparator.comparing(Student::getHeight).thenComparing(Student::getWeight))
.limit(10)
.collect(Collectors.toList());
From the requirements, although both Student and Classroom are StudentSources, the filtering and sorting always act on Student (they're never filtered or sorted by classroom, in your sample inputs). Filtering is pretty easy:
// interface with a single method, reduces to a lambda too
interface Filter<T> {
boolean accept(T candidate);
}
Sorting is canonically:
package java.util;
// interface with a single method, reduces to a lambda too
interface Comparable<T> {
int compareTo(T a, T b);
}
Both of the above are applications of the Visitor design pattern. As with the succinct answer by #Edwin, you line up your visitors in a pipeline (configuration phase) and then visit them (execution phase). Notice that the Visitor pattern has 'reasons' which um, students should read up on in their 'Gang of 4' book.
You don't say much about:
how the inputs are represented to the program (eg. as text which needs to be parsed)
whether the same student might conceivably appear in more than 1 classroom, or the list-of-students ... this has bearing on which Java collection you might choose to pass the Comparator to;
So the task at hand boils down to:
read the definitions of the filters, sorters, limiters, create visitors for these
read the data (classrooms/students), and for each student discovered, do if passesAllFilters(student) okstudents.add(student); where okstudents is a java.util.TreeSet primed with a Comparator, stop when limit is reached.
You could possibly quibble that the step which takes 'input that defines filter(s)' is a 'factory method', but that's really of no help .. List<Filter<Student>> getFilters(String filterSpec) doesn't really get you anywhere where a factory method is useful. Parsing the filters and coming up with code which references particular properties of Students, applies the expressions, etc, may not be a trivial task. Depending on the types of expressions your filters are required to permit, you might want to look into a compiler-generator like ANTLR 4. You'll likely need to use reflection.
take a look at https://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html
you can use multiple SortedMap (one for every key), in which you put every element of your list whit the corresponding key for every map (es: sortedMapAge.put(carl, 18) ..sortedMapHeight(carl,"1.75") ...).
so with iterator you can access your list members through the varius keys using the appropriate SortedMap.
And if you want to store alla that maps in a further abstraction layer you can store them in a hashmap and use as key the key identifier (sortedMapAge...key Age, sortedMapHeight height ....)
it's quite tricky but maps offer you a good ways to organize objects with keyset.
Personally, I'd do it like this:
public <E> List<E> query(List<E> dataset, Filter<E> filter, Comparator<E> sortOrder, int maxResults);
That is, I'd use generics to abstract over the input type, the command pattern for the filters and orders, and a plain int for the number of results to return.
The question is framed for List but easily applies to others in the java collections framework.
For example, I would say it is certainly appropriate to make a new List sub-type to store something like a counter of additions since it is an integral part of the list's operation and doesn't alter that it "is a list". Something like this:
public class ChangeTrackingList<E> extends ArrayList<E> {
private int changeCount;
...
#Override public boolean add(E e) {
changeCount++;
return super.add(e);
}
// other methods likewise overridden as appropriate to track change counter
}
However, what about adding additional functionality out of the knowledge of a list ADT, such as storing arbitrary data associated with a list element? Assuming the associated data was properly managed when elements are added and removed, of course. Something like this:
public class PayloadList<E> extends ArrayList<E> {
private Object[] payload;
...
public void setData(int index, Object data) {
... // manage 'payload' array
payload[index] = data;
}
public Object getData(int index) {
... // manage 'payload' array, error handling, etc.
return payload[index];
}
}
In this case I have altered that it is "just a list" by adding not only additional functionality (behavior) but also additional state. Certainly part of the purpose of type specification and inheritance, but is there an implicit restriction (taboo, deprecation, poor practice, etc.) on Java collections types to treat them specially?
For example, when referencing this PayloadList as a java.util.List, one will mutate and iterate as normal and ignore the payload. This is problematic when it comes to something like persistence or copying which does not expect a List to carry additional data to be maintained. I've seen many places that accept an object, check to see that it "is a list" and then simply treat it as java.util.List. Should they instead allow arbitrary application contributions to manage specific concrete sub-types?
Since this implementation would constantly produce issues in instance slicing (ignoring sub-type fields) is it a bad idea to extend a collection in this way and always use composition when there is additional data to be managed? Or is it instead the job of persistence or copying to account for all concrete sub-types including additional fields?
This is purely a matter of opinion, but personally I would advise against extending classes like ArrayList in almost all circumstances, and favour composition instead.
Even your ChangeTrackingList is rather dodgy. What does
list.addAll(Arrays.asList("foo", "bar"));
do? Does it increment changeCount twice, or not at all? It depends on whether ArrayList.addAll() uses add(), which is an implementation detail you should not have to worry about. You would also have to keep your methods in sync with the ArrayList methods. For example, at present addAll(Collection<?> collection) is implemented on top of add(), but if they decided in a future release to check first if collection instanceof ArrayList, and if so use System.arraycopy to directly copy the data, you would have to change your addAll() method to only increment changeCount by collection.size() if the collection is an ArrayList (otherwise it gets done in add()).
Also if a method is ever added to List (this happened with forEach() and stream() for example) this would cause problems if you were using that method name to mean something else. This can happen when extending abstract classes too, but at least an abstract class has no state, so you are less likely to be able to cause too much damage by overriding methods.
I would still use the List interface, and ideally extend AbstractList. Something like this
public final class PayloadList<E> extends AbstractList<E> implements RandomAccess {
private final ArrayList<E> list;
private final Object[] payload;
// details missing
}
That way you have a class that implements List and makes use of ArrayList without you having to worry about implementation details.
(By the way, in my opinion, the class AbstractList is amazing. You only have to override get() and size() to have a functioning List implementation and methods like containsAll(), toString() and stream() all just work.)
One aspect you should consider is that all classes that inherit from AbstractList are value classes. That means that they have meaningful equals(Object) and hashCode() methods, therefore two lists are judged to be equal even if they are not the same instance of any class.
Furthermore, the equals() contract from AbstractList allows any list to be compared with the current list - not just a list with the same implementation.
Now, if you add a value item to a value class when you extend it, you need to include that value item in the equals() and hashCode() methods. Otherwise you will allow two PayloadList lists with different payloads to be considered "the same" when somebody uses them in a map, a set, or just a plain equals() comparison in any algorithm.
But in fact, it's impossible to extend a value class by adding a value item! You'll end up breaking the equals() contract, either by breaking symmetry (A plain ArrayList containing [1,2,3] will return true when compared with a PayloadList containing [1,2,3] with a payload of [a,b,c], but the reverse comparison won't return true). Or you'll break transitivity.
This means that basically, the only proper way to extend a value class is by adding non-value behavior (e.g. a list that logs every add() and remove()). The only way to avoid breaking the contract is to use composition. And it has to be composition that does not implement List at all (because again, other lists will accept anything that implements List and gives the same values when iterating it).
This answer is based on item 8 of Effective Java, 2nd Edition, by Joshua Bloch
If the class is not final, you can always extend it. Everything else is subjective and a matter of opinion.
My opinion is to favor composition over inheritance, since in the long run, inheritance produces low cohesion and high coupling, which is the opposite of a good OO design. But this is just my opinion.
The following is all just opinion, the question invites opinionated answers (I think its borderline to not being approiate for SO).
While your approach is workable in some situations, I'd argue its bad design and it is very brittle. Its also pretty complicated to cover all loopholes (maybe even impossible, for example when the list is sorted by means other than List.sort).
If you require extra data to be stored and managed it would be better integrated into the list items themselves, or the data could be associated using existing collection types like Map.
If you really need an association list type, consider making it not an instance of java.util.List, but a specialized type with specialized API. That way no accidents are possible by passing it where a plain list is expected.