I have a design question to ask. I so far have not written any code, just thinking about how to implement at this point. I have an object of type A and it contains an object of type B. I would like B to define a category of objects (Interface or abstract class?). I then have an xml file that defines the sub-type that B should be. For instance, if B is an interface named Driveable, then "car" or "truck" might be defined in the xml as the Drivable object needed for type A.
What I was thinking of doing is making B an interface and then creating a static factory class that has a factory method to determine what sub-type B should be given an xml file. So my first question is would this be the best way to approach the problem? Would it be better to use an abstract class instead of an interface or is it mainly just personal preference?
Second, if I do go with an interface, then inside my factory method would I just do:
B createB(File f){
...
String type = ...
if(type.equals("car"))
return new CarType();
else if(type.equals("truck"))
return new TruckType();
...
return null;
}
So every time I add a new B sub-type, I would need to add another if statement to this method. Is there a better way to do this so all I would have to do is create a new B sub-type and then update my xml and not update the factory method? I essentially dont want to hard code in the types of B into my factory method. If what I have above is pretty standard protocol with factory methods, then I can deal with doing it that way, just doesnt quite seem right.
What you could do is define in xml the actuall classname that you want the B impls to be and then use the generic class constructor like this (missing error handling):
String bimplClassname = //read from xml
Class bimplClass = Class.forName(bimplClassname);
B newB = bimplClass.getConstructor(/*arg types*/).newInstance(/*args*/);
Growing off of carnold's example, your could create a map in your Factory Class that maps between the text in the xml and the corresponding java class.
private final static Map<String, Class> typeMap;
static {
typeMap = new HashMap<String, Class>();
typeMap.put("car", CarType.class);
typeMap.put("truck", TruckType.class);
}
and then in your method:
B createB(File f){
...
String type = ...
Class clazz = typemap.get(type);
if (clazz == null){
return null;
}
B newB = clazz.getConstructor(/*arg types*/).newInstance(/*args*/);
return newB;
}
Slightly easier to maintain than the if/else, but still have to maintain it.
I guess it depends on what triggers the creation of your objects. If it is some text that triggers the creation, then your existing code is fine for a small application. You could also choose a dependency injection framework like Guice.
Also, note that for comparing strings, you should use the .equals method, not == as shown in your code.
Related
I'm new to Java programming. While reading through the code of an open source project, I came across a line of code which I can't understand:
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
My questions are:
I usually call a constructor like this: final Type typeOfMap = new TypeToken<Map<String, Object>>(). I have never seen it followed by other pieces of code such as {}.getType(). What kind of syntax is this?
Is {} an object? Why can you call a function on it?
P.S. Type is java.lang.reflect.Type, and TypeToken is com.google.gson.reflect.TypeToken.
I'm also new at Java, but, as far as I know, that is a constructor that belongs to an abstract generic class new TypeToken<Map<String, Object>>() {} The class tiself may look something like this: public abstract class TypeToken<X> ... now, for the method .getType(). I'm not really sure how that is coded.
You reminded me that this is in my bucket list of things to learn/understand, but I'm pretty sure that this code pattern is a little too over engineered, (ofc this may be my bias precisely because I dont know it or what it could be useful for)
the .getType() method, may be a method inside the abstract that is public and non abstract.
I personally have found that in some cases (just in some), it is more convenient to instantiate abstract objects instead of extending them (which is how they are usually used), specially in cases when your abstract object needs another object created at an specific lifecycle, or when the abstract object needs interoperability within the same class.
Now If I'm not mistaken, I Think that THAT specific implementation com.google.gson.reflect.TypeToken makes use of reflect in order to get the class type of a non initialized object, without actually creating an object (maybe it does behind curtains), if you've tried to make a newInstance of an Array of nested generic classes, you know how it can become a headache, because of something called "erasure".
I usually call a constructor like this: final Type typeOfMap = new
TypeToken<Map<String, Object>>(). I have never seen it followed by
other pieces of code such as {}.getType(). What kind of syntax is
this?
It is a syntax for Anonymous inner classes.
Is {} an object? Why can you call a function on it?
Yes, you get an object from it. That's why a method can be invoked on it.
Anonymous classes are useful when you need a specific behaviour from a class for a single time. Like in below example, if you invoke sayHello on normal A object, then it will return Hello. But, the behaviour of sayHello method gets changed for object of anonymous class and it returns Bonjour this time.
public class SomeClass {
public static void main(String[] args) {
A defaultObj = new A();
A customObj = new A() {
#Override
public String sayHello() {
return "Bonjour";
}
};
System.out.println(defaultObj.sayHello());
System.out.println(customObj.sayHello());
}
}
class A {
String sayHello() {
return "Hello";
}
}
Output
Hello
Bonjour
Gson documentation for TypeToken also mentions about the reason and usage of anonymous class. The reason for usage in TypeToken class is that it is used to retrieve the type of token at runtime. As otherwise generic type information is not available at runtime because of type erasure.
https://www.javadoc.io/doc/com.google.code.gson/gson/2.6.2/com/google/gson/reflect/TypeToken.html
Represents a generic type T. Java doesn't yet provide a way to
represent generic types, so this class does. Forces clients to create
a subclass of this class which enables retrieval the type information
even at runtime. For example, to create a type literal for
List, you can create an empty anonymous inner class:
TypeToken<List> list = new TypeToken<List>() {};
I am using Java Reflection to initialize different types of objects. All of these objects are constructed the same way (namely, I pass in the same values to construct them).
Thus, my injector looks through each of the fields, and does a long if/else statement like the following:
if (Foo.class.isAssignableFrom(field.getType())
return new Foo(values);
else if (Bar.class.isAssignableFrom(field.getType())
return new Bar(values);
else if...//Continue over and over
I can't define an interface that requires the class to have a factory, because factories are static by nature. The same holds true for extending an abstract class.
Is there some way I can remove the above if/else statement so my injecting class has no idea about the classes that need injecting (besides the fact that it can be constructed with values?
As requested:
Have you looked at the Spring source code? This is a problem that has already been solved by an existing open source project and you can just fork the code and re-use it.
Use something like (untested):
private <T> T newInstance(Class<T> type){
Constructor<T> constructor = type.getConstructor(valueTypes);
return constructor.newInstance(values)
}
Then call:
Object obj = newInstance(field.getType());
where valueTypes are the types of the values.
is there a design pattern that I can make an object to have some kind of state where he starts as an extended object, but after some time turn back to its super.
For example - partial file inherits from a file and after its completed it goes to be a file.
No there is no type mutation in Java (and to be fair I can't think of any modern language having it).
What you may do, but it's clearly not exactly the same :
using a constructor taking your object as a parameter to build a new object in a different class (just like you can do new Float(new Double(2));). Note that this doesn't change the initial object so you have to assign again the variable(s) holding it.
add a type variable, based on an enum, indicating what's the nature of the object. For most purposes it's enough (and will save you from building an heavy type hierarchy).
Now, do you need type mutation ? If you just need to handle your object as if it was a direct instance of its superclass, you can do it already. The main difference with type mutation is that you call the overridden methods but that's normally fine if the type hierarchy was correctly designed.
And supposing I'd design a PartialFile class (supposing the name properly defines what it is), instead of using inheritance I would have used composition : I would have made a decorative class whose instance would have had a variable private File sourceFile.
This question is flawed - an extended Object is always an instance of its super class.
In your example, the following is valid...
public class PartialFile extends File{
// methods
}
PartialFile partFile = new PartialFile();
// do operations on partFile
File file = partFile;
// do operations on file
Because PartialFile extends File, you don't really need to 'turn it into its super class' - it already is an instance of the super class.
You can think of the PartialFile object as being a PartialFile, a File, an Object, and any other classes that it extends, all at the same time. You don't need to turn it between these different class types - just use it directly. For the above code, if you want to call the File.rename() method, both the following statements will do the same thing...
partFile.rename();
file.rename();
You don't need to change the partFile into a file to use the methods of the File object - just use them directly, as the Java VM knows that a PartialFile is also a File.
You can't really change a sub-type to be its super type - the Java VM will always know what type it really is - but you can trick it. If you use the following code...
PartialFile partFile = new PartialFile();
// do operations on partFile
File file = partFile;
// do operations on file
and then only every use file instead of partFile, you won't be able to use any of the PartialFile methods on it. It kinda disguises that its a PartialFile, but it doesn't actually convert it.
If you do something like this...
public File createFile(){
PartialFile partFile = new PartialFile();
// operations on partFile
return partFile;
}
File file = createFile();
// operations on file
You can create and use a PartialFile in the method, but when you're finished you return it as a simple File. Whenever you refer to this object from now on, the Java VM will pretend that its a File. However, technically it will always be a PartialFile, and it doesn't stop you casting it back into a PartialFile if you want to, like so...
PartialFile partFile = (PartialFile)file;
// operations on partFile
So its just a disguise.
A subclass is already an instance of its superclass, so you can just cast it to its superclass
class PartialFile extends File {
// Code...
}
PartialFile partialFile;
// Code...
File file = (File) partialFile;
Use design pattern State and/or a Factory method.
You may still have to do some refactoring, as you would most likely need an Interface/abstract base class for the super.
Something like this:
class MySwitcher implements SuperInterface {
private final SuperInterface super = new Super();
private final SuperInterface subclass = new Subclass();
private SuperInterface current = super; // Start in state "behaves as super"
// Method from SuperInterface
public MyResult doAction(final MyData d) {
final MyResult res = current.doAction(d);
current = setImplementationBasedOnResOfDoAction(res);
return res;
}
}
I need to have some sort of data structure that can contain heterogenous subclasses of the same superclass, all of which I have implemented myself.
So far, I am attempting to have an ArrayList<SuperClass> list = new ArrayList<SuperClass>();
and then, I am assuming I will be able to cast each slot of list into either of the subclasses, but this is not working out so well.
I need an efficient way to do the aforementioned.
Thanks!
You can do it with any data structure that exists, I would recommend a List or a Set. For instance:
Collection<Super> supers = new ArrayList<Super>();
Now when you say this:
I am assuming I will be able to cast each slot of list into either of
the subclasses,
That is an invalid assumption. The collection will hold any object that extends Super however you cannot arbitrarily cast each element into whatever you want. You would need to do an instanceof test on each element if you are looking for that type of functionality, example follows:
for(Super currentSuper : supers)
{
if(currentSuper instanceof SubA)
{
SubA subA = (Suba) currentSuper);
// do stuff with subA
}
else if(currentSuper instanceof SubB)
{
SubB subB = (SubB) currentSuper);
// do stuff with subB
}
}
Scope as need be.
Now on the point of Vlad:
and much better design would be not to test what the actual class is,
but just to call a virtual method, which will do the right thing in
any case
If you can guarantee the functionality of all potential sub-classes and have no issues with people overriding your classes (in the event you haven't marked them final) you do not need to do the instance of test. Instead your code could be as simple as:
for(Super currentSuper : supers)
{
currentSuper.doSomethingNifty();
}
Let's say you have some Java code as follows:
public class Base{
public void m(int x){
// code
}
}
and then a subclass Derived, which extends Base as follows:
public class Derived extends Base{
public void m(int x){ //this is overriding
// code
}
public void m(double x){ //this is overloading
// code
}
}
and then you have some declarations as follows:
Base b = new Base();
Base d = new Derived();
Derived e = new Derived();
b.m(5); //works
d.m(6); //works
d.m(7.0); //does not compile
e.m(8.0); //works
For the one that does not compile, I understand that you are passing in a double into Base's version of the m method, but what I do not understand is... what is the point of ever having a declaration like "Base b = new Derived();" ?
It seems like a good way to run into all kinds of casting problems, and if you want to use a Derived object, why not just go for a declaration like for "e"?
Also, I'm a bit confused as to the meaning of the word "type" as it is used in Java. The way I learned it earlier this summer was, every object has one class, which corresponds to the name of the class following "new" when you instantiate an object, but an object can have as many types as it wants. For example, "e" has type Base, Derived, (and Object ;) ) but its class is Derived. Is this correct?
Also, if Derived implemented an interface called CanDoMath (while still extending Base), is it correct to say that it has type "CanDoMath" as well as Base, Derived, and Object?
I often write functions in the following form:
public Collection<MyObject> foo() {}
public void bar(Collection<MyObject> stuff){}
I could just as easily have made it ArrayList in both instances, however what happens if I later decide to make the representation a Set? The answer is I have a lot of refactoring to do since I changed my method contract. However, if I leave it as Collection I can seamlessly change from ArrayList to HashSet at will. Using the example of ArrayList it has the following types:
Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess
There are a number of cases where confining yourself to a particular (sub)class is not desired, such as the case you have where e.m(8.0);. Suppose, for example, you have a method called move that moves an object in the coordinate graph of a program. However, at the time you write the method you may have both cartesian and radial graphs, handled by different classes.
If you rely on knowing what the sub-class is, you force yourself into a position wherein higher levels of code must know about lower levels of code, when really they just want to rely on the fact that a particular method with a particular signature exists. There are lots of good examples:
Wanting to apply a query to a database while being agnostic to how the connection is made.
Wanting to authenticate a user, without having to know ahead of time the strategy being used.
Wanting to encrypt information, without needing to rip out a bunch of code when a better encryption technique comes along.
In these situations, you simply want to ensure the object has a particular type, which guarantees that particular method signatures are available. In this way your example is contrived; you're asking why not just use a class that has a method wherein a double is the signature's parameter, instead of a class where that isn't available. (Simply put; you can't use a class that doesn't have the available method.)
There is another reason as well. Consider:
class Base {
public void Blah() {
//code
}
}
class Extended extends Base {
private int SuperSensitiveVariable;
public setSuperSensistiveVariable(int value) {
this.SuperSensistiveVariable = value;
}
public void Blah() {
//code
}
}
//elsewhere
Base b = new Extended();
Extended e = new Extended();
Note that in the b case, I do not have access to the method set() and thus can't muck up the super sensitive variable accidentally. I can only do that in the e case. This helps make sure those things are only done in the right place.
Your definition of type is good, as is your understanding of what types a particular object would have.
What is the point of having Base b = new Derived();?
The point of this is using polymorphism to change your implementation. For example, someone might do:
List<String> strings = new LinkedList<String>();
If they do some profiling and find that the most common operation on this list is inefficient for the type of list, they can swap it out for an ArrayList. In this way you get flexibility.
if you want to use a Derived object
If you need the methods on the derived object, then you would use the derived object. Have a look at the BufferedInputStream class - you use this not because of its internal implementation but because it wraps an InputStream and provides convenience methods.
Also, I'm a bit confused as to the meaning of the word "type" as it is used in Java.
It sounds like your teacher is referring to Interfaces and Classes as "types". This is a reasonable abstraction, as a class that implement an interface and extends a class can be referred to in 3 ways, i.e.
public class Foo extends AbstractFoo implements Comparable<Foo>
// Usage
Comparable<Foo> comparable = new Foo();
AbstractFoo abstractFoo = new Foo();
Foo foo = new Foo();
An example of the types being used in different contexts:
new ArrayList<Comparable>().Add(new Foo()); // Foo can be in a collection of Comparable
new ArrayList<AbstractFoo>().Add(new Foo()); // Also in an AbstractFoo collection
This is one of the classic problems on object oriented designs. When something like this happens, it usually means the design can be improved; there is almost always a somewhat elegant solution to these problems....
For example, why dont you pull the m that takes a double up into the base class?
With respect to your second question, an object can have more than one type, because Interfaces are also types, and classes can implement more than one interface.