I have the following
public abstract class MyData
{
private String sID;
public void setsID(String sID) {
this.sID= sID;
}
public String getsID() {
return sID;
}
}
This base class is being extended by 2 other classes
public class DataTypeOne extends MyData
{
private String sName;
public void setsName(String sName) {
this.sName= sName;
}
public String getsName() {
return sName;
}
}
public class DataTypeTwo extends MyData
{
private String sSummary;
public void setsSummary(String sSummary) {
this.sSummary= sSummary;
}
public String getsSummary() {
return sSummary;
}
}
I am initializing this class as follows
MyData oDataOne = new DataTypeOne();
MyData oDataTwo = new DataTypeTwo();
Reason for that is that I have a factory method which shall give me the class based on type (One or two)
With oDataOne & oDataTwo, I am able to access getsID() from the base class but not the getters & setters of the respective class.
How can I access those? I
You can't access a method that doesn't exist. All you've promised your Java compiler is that oDataOne and oDataTwo are MyData objects. Since the MyData class doesn't have the implementation-specific methods, you cannot ask Java to call those methods (since it doesn't think they exist).
If you want to access those methods, you need to either cast the object to a class that actually has the right methods, or you can add abstract method stubs to your base class, which will tell Java that those methods actually exist.
Type casting is simpler to write in the short term, but less clear, and you may run into more trouble down the road:
((DataTypeOne) oDataOne).getsName();
((DataTypeTwo) oDataOne).getsSummary(); // Throws ClassCastException!
Adding abstract stubs is more robust, but may not make sense if not all concrete subclasses should implement all abstract methods:
public abstract class MyData {
public abstract void setsName(String name);
public abstract String getsName();
public abstract void setsSummary(String summary);
public abstract String getsSummary();
}
public class DataTypeOne extends MyData {
public String getsName() {
// implement
}
public void setsName(String name) {
// implement
}
// Still have to implement these!!!
public String getsSummary() {
// raise an exception or something if appropriate
}
public void setsSummary(String summary) {
// raise an exception or something if appropriate
}
}
// Same for DataTypeTwo
Since you declared the variable as a MyData, you can only access the methods of MyData. You can get to the subclass methods by casting it to DataTypeOne or DataTypeTwo:
((DataTypeOne)oDataOne).getsName()
But you need to be sure it is of type DataTypeOne or you will get a ClassCastException
MyData oDataOne = new DataTypeOne();
this says, that your oDataOne object is of the type MyData. Even if it is created as a DataTypeOne, java can only be sure that it is defiantly a MyData instance.
If you are sure that the MyData instance is in reality also a DataTypeOne instance, you can cast and then access the DataTypeOne methods + the MyData methods.
To make sure that an object is of a specific type test:
if(oDataOne instanceOf DataTypeOne){
((DataTypeOne) oDataOne).getsName(); // this will return the Name if oDataOne is really of the type DataTypeOne
}
An object of type MyData has no knowledge of whether any other classes extends it or not, so there is no way to access members of those classes.
You will have to cast your object to the specific type to access the specific members.
If you find yourself in this situation, you can be pretty sure that your design is flawed. If you need to perform a specific action for each type of MyData extension, add a method, e.g specialAction() to the interface and hide the specifics in there. That eliminates the entire need to find out which subclass you are dealing with.
Related
Consider the following code:
public interface MyClass {
public final String getMyObject1();
public final String getMyObject2();
}
public class MyClass1 implements MyClass {
private String myObject1;
private String myObject2;
public MyClass1(String myObject1, String myObject2) {
this.myObject1 = myObject1;
this.myObject2 = myObject2;
}
public String getMyObject1() {
return myObject1;
}
public String getMyObject2() {
return myObject2;
}
}
public interface MyClass2 extends MyClass {
public static MyClass2 newInstance(String myObject1, String myObject2) {
return new MyClass2() {
public String getMyObject1() {
return myObject1;
}
public String getMyObject2() {
return myObject2;
}
};
}
}
And I use them like
public static void func(MyClass m) {
m.getMyObject1();
m.getMyObject2();
}
func(new MyClass1(o1, o2));
func(MyClass2.newInstance(o1, o2));
I wonder how they differ and if I only need to read from the values (i.e. to use MyClass as a "struct" to pass values), using the anonymous class can it be a simpler approach?
Otherwise, what are the draw backs?
One core rule of programming: try to not surprise your readers.
Your approach here to use a static class within an interface as "factory" method is very surprising (and believe me: I have seen a lot of Java code).
If at all, the more "common" way of handling such things: create a static class with a slightly similar name, you know, like there is java.lang.Object and java.lang.Objects that carries some useful static helper methods.
And beyond that, there is already a class in Java that helps with arbitrary numbers of "named" values; and that is called a Map!
Finally: there are some good arguments for "DTO"s (data transfer objects) but esp. for "beginners", you should rather look into "real" OO designs; based on the SOLID principles. In that sense: design real classes that exactly model your problem domain; and that provide helpful abstractions. A struct with an arbitrary number of members ... doesn't fall into either category.
The problem here is not the code necessarily but the design. I would be interested to know the real world use case you are trying to design here.
Surely there are limitations in the second approach like you cannot update the value of your objects at all once your class is created as you just have a way to get the value of the passed objects back.
Coming back to Design:
An interface is supposed to be an action which your class can perform if it implements that interface. In your case you are trying to return the value of two instance variables using the two methods in your interface which is a kind of action but it ignores the basic principle of encapsulation.
If your class defines/owns those instance variables it should have the getters and setters for that. You should not require an interface to do that. So ideally your interface should not be required. Any other class which uses MyClass1 object should directly use the getters and setters of the MyClass1.
I haven't quite found an elegant way to solve this issue. I have an abstract class that several other classes are inheriting with an abstract method that can contain anywhere from zero to 4-5 arguments of varying types.
public abstract class Item {
public abstract void use();
}
For instance, I have a Book class that inherits this and takes no arguments when overriding use(), I have a Key class that inherits and takes a String and a Queue as arguments when overriding, etc...
I've tried using generics but I have to input the number used, such as Item, when it actually depends on the class.
public abstract class Item<T,U> {
public abstract void use(T arg1, U arg2); //Number of arguments/types could be more or less
}
I've tried sending a variable list of Objects but the object types are always variable and I've unsure as to the syntax to receive in the inheriting classes.
public abstract class Item<T> {
public abstract void use(T... arguments);
}
public class Book extends Item<?> {
public void use(?);
}
public class Book extends Item<String, Queue> { //Wrong number of arguments since I can't use Item<T...>
public void use(String str, Queue q); //fails
}
I may just be doing something wrong - can anyone offer any assistance or insight?
I've struggled with the same question, and there's not a perfect answer, but I can give you a few things to consider. First, you're basically trying to do something that is inherently against Object Oriented Programming, which is that you're trying to create a variable interface. The point of an interface is that code that gets an abstract version of the object (the Item rather than the Book, for example), knows how to invoke the use() method. This means that they must know what can be passed to the use() method. If the answer depends on the implementation of the abstract class or interface, then you need to ensure that the code using it actually knows what kind of implementation (Book, etc.) that it's using, otherwise it's not going to know how to invoke use() with the appropriate parameters anyway. It sounds like you need to refactor your code, in all honesty.
However, there is a way to answer your question as stated without refactoring the architecture. You could create a class that's data is all of the different types of parameters that could possibly be passed to the use() method, have the calling code set the fields of that class, and then pass that to the use() method. For example:
public class UseParameters {
private String string;
private Queue queue;
// Any other potential parameters to use(...)
public void setString(String string) {
this.string = string;
}
public String getString() {
return string;
}
// All of the other accessor methods, etc.
}
Then, you could define the use method in Item like this:
public abstract void use(UseParameters params);
And any code using an Item would have to set the parameters of the object appropriately:
Item item = // However you're going to get the item
UseParameters params = new UseParameters();
params.setString("good string");
params.setQueue(new Queue());
item.use(params);
I just want to point out that if the code above knows the Item is a Book (which is how it knows to set the String and Queue, then why not just get a Book and skip needing an abstract class with a variable use() method altogether? But I digress. Anyway, the Book would then implement the use() method like so:
#Override
public void use(UseParameters params) {
if(params.getString == null || params.getQueue() == null)
// throw exception
// Do what books do with strings and queues
}
I think that gets you what you want, but you should consider refactoring, I think.
What you want is the Value Object Pattern.
Define a class that encapsulates the various parameter types into one value object, and have the abstract method accept a parameter of this type. Each variation of parameters you were considering would have its own value class.
Then simply add a generic type to the class and have the abstract method accept a parameter of that type:
public abstract class Item<V> {
public abstract void use(V v);
}
To use it, suppose MyItem needs a value object of type MyValueClass:
public class MyItem extends Item<MyValueClass> {
public void use(MyValueClass v) {
}
}
If the types to be used as argument are always variable I don't see a reason to use generics. Just use plain Object type:
public abstract class Item {
public abstract void use(Object ... arguments);
}
public class Book extends Item {
public void use(Object ... arguments) { ... }
}
The best approach I can think of is to group the items according to the behavior of their use() method.
Example
public abstract class QueueableItem {
public abstract void use(String, Queue);
}
public abstract class OrdinaryItem{
public abstract void use(String);
}
If the grouped items share a common behavior (common as in same method signature & return value), you can define and extend a parent class that will contain the definition of this common behavior.
Yes, we can provide parameters to abstract method but it is must to provide same type of parameters to the implemented methods we wrote in the derived classes.
I am currently trying to achieve something like this:
Based on this class, I try to create a new instance of the class Class<? extends AbstractValidator> returned by the method getValidator().
public abstract class AbstractEnumDefinition
extends AbstractRequestFieldDefinition {
private Vector<String> values = new Vector<String>();
public abstract void define(String lang);
protected void addEnumDefinition(String value){
values.add(value);
}
public Vector<String> getValues(){
return values;
}
#Override
public Class<? extends AbstractValidator> getValidator() {
return new AbstractValidator() {
#Override
public boolean isValid(String value) {
return values.contains(value);
}
#Override
public String getDefaultValue() {
return "";
}
}.getClass();
}
}
Say I create this class:
public class LanguageDefinition extends AbstractEnumDefinition {
public LanguageDefinition() {
super();
}
#Override
public void define(String language) {
addEnumDefinition("BEL-fr");
addEnumDefinition("BEL-nl");
addEnumDefinition("BEL-en");
}
}
Later in my code, I call
new LanguageDefinition().getValidator().getConstructor().newInstance()
The class I am trying to instantiate here is not declared anywhere, but "generated dynamically"/"dynamically created" within the AbstractEnumDefinition class.
When trying to do this, I get an java.lang.InstantiationException for
be....servlets.model.extraction.filter.editor.AbstractEnumDefinition$1
I guess this is due to the fact that this Class has to be explicitly created before hand, and not referenced dynamically?
Is there some kind of solution that would allow me to not have to write one class per validator?
Thanks for the help,
Eric
I can only make assumptions since i don't see the code where you are actually using the class, but you should check: http://docs.oracle.com/javase/6/docs/api/java/lang/InstantiationException.html
One thing it mentions is the instantiation can fail is the class is an abstract class (perfectly logical since you can't instantiate abstract classes).
Also, i don't see why you need to return the class and then create and object. Why not just define a Validator Interface and have your method return a Validator object.
That does not work for anonymous classes as far as I know, you have to convert your class to a named inner class:
But even that will not work, properly because you might not have a default constructor. Inner classes get implicit constructor arguments to keep the reference to the enclosing class. Unfortunately Closures do not work so well in static languages.
In summary inner classes that are non-static can not be instantiate outside of an instance of the enclosing class.
In Java I have two classes:
Class A
{
public String ID;
public Object Name;
}
Class B
{
public String ID;
public Object Name;
}
I want to have a method where I can pass it either a Class A or B object:
public void SomeMethod(??? arg)
{
String id = arg.ID;
Object name= arg.Name;
}
Is it possible to pass an object of either class A or B to this method? If so, how is the method's signature written?
The only solution I can think of is to create an interface that both Class A and B implements containing get and set methods to set the fields ID and Name. Then the method's signature would be a parameter whose type is the interface. I was hoping that maybe there is a simpler way, possibly with generics?
You are correct with needing to use an interface (or an abstract class) with the appropriate method signatures. To java the two class are different with nothing (beside Object) in common. You need to create a class hierarchy refelecting the commonality between them.
Use method overloading.
public void SomeMethod(A arg)
{
String id = arg.ID;
Object name= arg.Name;
}
public void SomeMethod(B arg)
{
String id = arg.ID;
Object name= arg.Name;
}
You could make an interface and have A and B implement it. It really depends on your application. For small programs, I would just stick with method overloading since it just introduces unnecessary abstraction into your program.
For larger applications where extensibility is a priority, you may want to consider using an interface. Suppose later on you want to write classes C and D which also have SomeMethod(). Using an interface makes it so that you don't have to go through your entire code and overload appropriate methods over and over again.
If you know for sure that A and B are the end of the story, then there's no need to make an interface.
EDIT: If there's a lot of code to be duplicated, then make a helper method:
public void SomeMethod(A arg)
{
HelpMePlease( arg.ID, arg.Name );
}
public void SomeMethod(B arg)
{
HelpMePlease( arg.ID, arg.Name );
}
private void HelpMePlease( String id, Object name ) {
// 1000 lines of code here
}
You don't need generic types. Simple inheritance will do the job
abstract class Base {
public String ID;
public Object Name;
}
class A extends Base {
}
class B extends Base {
}
public void SomeMethod(Base arg)
{
String id = arg.ID;
Object name= arg.Name;
}
Generics are intended to improve type safety during compilation.
What you are asking about seems to be something akin to C++ concepts or various other languages' duck typing.
In Java, if some sequence of operations need to be performed on two disparate types, you need to introduce an interface or resort to scripting/reflection.
Define two interfaces, hasID and hasName, and then:
public class MyClass<A extends hasID & hasName>{
public void SomeMethod(A object) {
String id = object.getID();
Object name= object.getName();
}
}
Where getID and getName are defined on their respctive interfaces.
What I mean is:
public class SomeBackingBean {
protected String someString;
public void setSomeString (String str) {
this.someString = str;
}
public String getSomeString {
return someString;
}
}
It was just a general case for a general answer.
Now second example:
public abstract class AbstractBean<T extends EntityInterface> {
protected T entity;
public void setEntity (T t) {
this.entity = t;
}
public void getEntity () {
return entity;
}
protected ReturnType calculateSomethingCommon () {
//use entity (knowing that it implements EntityInterface)
//to implement some common for all subclasses logic
}
}
public class ConcreteBean extends AbstractBean<ConcreteEntity> {
...
//and here we can write only specific for this bean methods
...
}
Is second example an example of bad practice too?
In general, protected variables violate object oriented principles. You're giving other objects direct access to member variables. By doing so, you form tighter coupling and it makes it harder to change the variable, since other objects are directly using it. It also means you can't do things like validate when it's set, add logging around getters/setters, etc.
If, for example, you have a PropertyChangeListener registered to properties for a bean, any registered listeners might not be notified if a protected property is changed directly by a sub-class.