Base class storing a reference to child variable? - java

Is there any advantage to storing a reference to a child instance field in the base class, as opposed to always calling an abstract getter when accessing it in the base class?
Suppose I have a base class like below:
public abstract class BaseClass {
abstract String getText();
public void printText() {
System.out.println(getText());
}
}
And a child class like below where getText() is returning a field that will never change.
public ChildClass extends BaseClass {
private String text = "blah";
#Override
public String getText() {
return text;
}
}
Is there any advantage/disadvantage to converting to the below instead?
public abstract class BaseClass {
abstract String getText();
private String text;
public void printText() {
System.out.println(text);
}
#PostConstruct
public void postConstruct() {
this.text = getText();
}
}

Regarding the use of PostConstruct, and I will refer you to this question to elaborate on that part, but essentially in combination with dependency injection/polymorphic methods it can make sense to use it to make sure you have a fully initialized object.
In general I would say the two approaches you suggest are not equivalent, because the classes have different behavior. For your second class it is guaranteed that for every call to printText() the same text will be printed, whereas for your first version, the text may be different every time, since the implementation of getText() is delegated to the implementing child-class. Thus the second version has an invariant the first one does not. Whether or not this is desirable or not is another question you need to evaluate in your concrete context.

Related

Abstract method with variable list of arguments

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.

Java - Update Object from another class

How can I update an object in class A from a method in class B without using the return?
for example:
public class A {
//my main class
private javax.swing.JTextField txtField1;
//a text field (txtField1) is initialized in this class and drawn
}
public class B {
public void doSomething(){
//does something and updates the txtField1 in class A
}
}
and once again, I do not wish to use return since my return is already returning another value from the same method.
There are many ways you could achieve this. The simplest would be to pass the object into the method in class B:
public void doSomething(JTextField fieldToUpdate){
//your logic here
fieldToUpdate.setText("something");
}
Then you can just update fieldToUpdate directly. This is not a great design pattern since it directly exposes control of a variable owned by 1 class to another.
Another alternative is to pass the instance of Class A into the method and call public methods on it:
public void doSomething(A aInstance){
//your logic here
aInstance.setText("something");
}
then in class A you'd need to define
public void setText(String text){
txtField1.setText(text);
}
This is a little better since class B doesn't have direct access to the internals of Class A.
An even more encapsulated response (though probably overkill for a case this simple) is to define an Interface and pass an instance of a class that implements the interface to the method in class B:
public void doSomething(TextDisplayer txt){
//your logic here
txt.setText("something");
}
then in class a:
public class A implements TextDisplayer{
public void setText(String txt){
txtField1.setText(txt);
}
}
then the interface:
public interface TextDisplayer{
public void setText(String txt);
}
The advantage of this approach is that it keeps class B completely decoupled from the class A. All it cares about is that it is passed something that knows how to handle the setText method. Again, in this case it is probably overkill, but it is the approach that keeps your classes as decoupled as possible.
You either need to call a method in class A, or make the text field static (bad idea).
Depending on usage, class A could instantiate a B as a swing worker/etc. and give B the specific information it needs. It could also be the other way around, B instantiates an `A.
assume you have a public setter method in A to change the value of txtField1. (because the property you want to change has keyword "private")
say in A, you have
public void setTxtField1Value(String newValue){
this.txtField1.value=newValue; // using the right method in api. I am not familiar with gui..
}
then in B, the method would be:
public class B {
public void doSomething(A a){
//does something and updates the txtField1 in class A
a.setTxtField1Value("foobar");
}
}

How to pass generic parameters in Java

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.

Why not abstract fields?

Why can't Java classes have abstract fields like they can with abstract methods?
For example: I have two classes that extend the same abstract base class. These two classes each have a method that is identical except for a String constant, which happens to be an error message, within them. If fields could be abstract, I could make this constant abstract and pull the method up into the base class. Instead, I have to create an abstract method, called getErrMsg() in this case, that returns the String, override this method in the two derived classes, and then I can pull up the method (which now calls the abstract method).
Why couldn't I just make the field abstract to begin with? Could Java have been designed to allow this?
You can do what you described by having a final field in your abstract class that is initialised in its constructor (untested code):
abstract class Base {
final String errMsg;
Base(String msg) {
errMsg = msg;
}
abstract String doSomething();
}
class Sub extends Base {
Sub() {
super("Sub message");
}
String doSomething() {
return errMsg + " from something";
}
}
If your child class "forgets" to initialise the final through the super constructor the compiler will give a warning an error, just like when an abstract method is not implemented.
I see no point in that. You can move the function to the abstract class and just override some protected field. I don't know if this works with constants but the effect is the same:
public abstract class Abstract {
protected String errorMsg = "";
public String getErrMsg() {
return this.errorMsg;
}
}
public class Foo extends Abstract {
public Foo() {
this.errorMsg = "Foo";
}
}
public class Bar extends Abstract {
public Bar() {
this.errorMsg = "Bar";
}
}
So your point is that you want to enforce the implementation/overriding/whatever of errorMsg in the subclasses? I thought you just wanted to have the method in the base class and didn't know how to deal with the field then.
Obviously it could have been designed to allow this, but under the covers it'd still have to do dynamic dispatch, and hence a method call. Java's design (at least in the early days) was, to some extent, an attempt to be minimalist. That is, the designers tried to avoid adding new features if they could be easily simulated by other features already in the language.
Reading your title, I thought you were referring to abstract instance members; and I couldn't see much use for them. But abstract static members is another matter entirely.
I have often wished that I could declare a method like the following in Java:
public abstract class MyClass {
public static abstract MyClass createInstance();
// more stuff...
}
Basically, I would like to insist that concrete implementations of my parent class provide a static factory method with a specific signature. This would allow me to get a reference to a concrete class with Class.forName() and be certain that I could construct one in a convention of my choosing.
Another option is to define the field as a public (final, if you like) in the base class, and then initialize that field in the constructor of the base class, depending upon which subclass is currently being used. It's a bit shady, in that it introduces a circular dependency. But, at least it's not a dependency that can ever change -- i.e., the subclass will either exist or not exist, but the subclass's methods or fields can not influence the value of field.
public abstract class Base {
public final int field;
public Base() {
if (this instanceof SubClassOne) {
field = 1;
} else if (this instanceof SubClassTwo) {
field = 2;
} else {
// assertion, thrown exception, set to -1, whatever you want to do
// to trigger an error
field = -1;
}
}
}

Java Inheritance Question

I Have something similar to this setup:
public class Base {
public String getApple() {return "base apple"};
}
public class Extended extends Base{
public String getApple() {return "extended apple"};
}
Somewhere else in the code I have this:
{
Base b = info.getForm();
if (b instanceof Extended){
b = (Extended) b;
}
System.out.println(b.getApple()); // returns "base apple" even when if clause is true why??
}
How do I accomplish that?
First:
if (b instanceof Extended){
b = (Extended) b;
}
does absolutely nothing. You are basically saying b = b, which says nothing. You are not even changing the reference.
Second, getApple() will always be dynamically bound, and the "extended apple" should always be called - given that the subclass is truly extending the base class, and the method is truly overridden.
Basically what you need to do, in order to accomplish correct getApple() behavior:
remove the if clause. it does nothing.
make sure your class is indeed extending the base class
make sure the getApple() method is overriding the base class method. (use the #override annotation if you are not sure)
As written, your code will not compile, which makes me think that your problem is elsewhere. Your return statements don't have semicolons at the end of them. Rather, they appear after the }. It's possible you had some other problem (maybe your subclass misspelled getApple()), but you're still using your old class files because your new stuff isn't compiling.
This code works:
class Base {
public String getApple() { return "base apple"; }
}
class Extended extends Base {
public String getApple() { return "extended apple"; }
}
public class Test {
public static void main(String[] args) {
Base b = new Extended();
System.out.println(b.getApple());
}
}
Console:
#javac Test.java
#java Test
extended apple
First of all, that if block should never be necessary. It's basically a no-op.
Second, this isn't your real code, because it doesn't even compile. You're missing semicolons after the return statements.
I suspect that your problem is that your real code has a typo that's making the signatures of the two getApple methods different. This means that Extended has two methods: the one inherited from Base and the one with a different signature in itself. Since you're calling with the signature of the Base.getApple method, you're always getting that behavior. This is only a guess though, as your posted code does not exhibit the problem you describe.
Yuval is right that your cast in the if block has no effect. You might try combining your last statement with the if:
if (b instanceof Extended)
{
// Prints "extended apple" if reached.
System.out.println(((Extended)b).getApple());
}
Add #Override to the method in your subclass and recompile. This will help you find out if you're not actually overriding the method you think you are.
i.e.
public class Base {
public String getApple() {return "base apple";}
}
public class Extended extends Base{
#Override
public String getApple() {return "extended apple";}
}
The only way to get that behavior is to return super.getApple() in your extended class, which is effectively the same as not overriding it in the first place. The only way this could help is if you pass in an argument to decide which to return. Not saying thats good design...
Forgot to mention that, as Yuval said, the cast does nothing to the object.
You should investigate what is constructing your instance that is returned from info.getForm(). You may want to make the Base abstract to prevent it from being instantiated and you'll quickly see where construction is happening.
Are you sure your code example provided in your question EXACTLY matches the code your are using? The reason I ask is that the behavior you are describing happens when you access a public FIELD instead of a public METHOD with an object pointer.
For example:
public class BaseClass {
public String baseField;
public BaseClass() {
baseField = "base";
}
public String getBaseField() {
return baseField;
}
}
public class SubClass extends BaseClass {
public String baseField;
public SubClass () {
baseField = "sub";
}
public String getBaseField() {
return baseField;
}
}
public class MainClass {
public static void main(String[] args) {
BaseClass baseObject = new BaseClass();
SubClass subObject = new SubClass();
System.out.println(baseObject.getBaseField());
System.out.println(subObject.getBaseField());
System.out.println(baseObject.baseField);
System.out.println(subObject.baseField);
System.out.println(((BaseClass)subObect).getBaseField());
System.out.println(((BaseClass)subObect).baseField);
}
}
Will print out:
base
sub
base
sub
sub
base
When you call a method, the JVM will start at the bottom of the inheritance hierarchy and call the appropriate method. When you reference a field instead, it uses the class of the pointer instead of walking up the class hierarchy to resolve the value. The behavior of the field reference matches what you're seeing, which is why I ask for clarification/verification.

Categories

Resources