I tried to keep the code as generic as possible, this only represents
the basic setup. I am a Java beginner trying to understand Interfaces, Classes
and Methods. I did change the Interface name and Class names to make referencing
them easier. I am fully aware that this code as it is won't compile.
I am trying to understand the concept.
Given is an Interface, with an existing InterfaceClass and another class
using the interface.
Interface:
public interface IInterface extends Comparable<IInterface>{
String getContent() throws DumbException;
}
Class:
public class InterfaceClass implements IInterface{
public String getContent() throws DumbException {
// here I would need a parameter (filepath) to get a file
// and read its content and return the content as string
// however the interface doesn't provide a parameter for this
// method. So how is this done?
}
}
The class using the method:
public class Frame extends AbstractFrame {
public void setDetails(IInterface details) {
// This is the call I don't understand...
details.getContent();
}
}
The part I don't understand is:
How does the details object give any parameter to getContent()?
I mean I don't even see this object being defined other than IInterface details
Solution 1
You can redefine IInterface to
public interface IInterface extends Comparable<IInterface>{
String getContent(String filepath) throws DumbException;
}
public class InterfaceClass implements IInterface{
public String getContent(String filepath) throws DumbException {
// use filepath to get the file's content
}
}
Usage is
public class Frame extends AbstractFrame {
public void setDetails(IInterface details) {
details.getContent("/path/to/some/folder");
}
}
Solution 2
You can't change IInterface but you add a constructor to InterfaceClass
public class InterfaceClass implements IInterface{
private String filepath;
public InterfaceClass(String filepath) {
this.filepath = filepath;
}
public String getContent() throws DumbException {
// use filepath to get the file's content
}
}
Usage is
new Frame().setDetails(new InterfaceClass("path/to/some/folder"));
You can pass a data in constructor in base class
public class InterfaceClass implements IInterface{
private String data;
public InterfaceClass(String data) {
this.data = data;
}
public String getContent() throws DumbException {
//do something here with data
// here I would need a parameter (filepath) to get a file
// and read its content and return the content as string
// however the interface doesn't provide a parameter for this
// method. So how is this done?
}
}
You can use this class now:
IInterface myNewClass = new InterfaceClass("blablabla");
frameClass.setDetails(myNewClass);
And pass it to second class.
details is the argument passed to setDetails as type implementing IInterface. Anything that implements IInterface can be used as details, since the interface gives you contract assurance that getContent is in fact a strict member for that implementation.
public interface IInterface extends Comparable<IInterface>{
String getContent() throws DumbException;
}
public class InterfaceClass implements IInterface{
public String getContent() throws DumbException {//this method is of string type so you must provide return type
return "some details";
}
}
public class Frame extends AbstractFrame {
public void setDetails(IInterface details) {
System.out.println(details.getContent()); //output:- some details
}
}
public class SomeClass{
public void someMethod(){
new Frame().setDetails(new InterfaceClass)
}
}
Just pay note here to SomeClass. In SomeClass you are passing object of extended class i.e interfaceClass (and this is ploymorphism).
And like you did ,you need to pass object to interface variable like IInterface details=new InterfaceClass() or some any other class that implements IInterface but note that the class must extend thatIInterfaceand in your case it isinterfaceClass`
If you fail to that it will throw nullpointerExecption because it is just a reference variable , so you need to pass the object of actual class with that method and ploymorphism will handle rest.
note This is common way to access child classes and provides loose coupling and if you'll work on spring you'll know better.
Hope it helps
Related
I have the following scenario in Java. Let's say I have an interface, and two classes that implement this interface. As follows:
public interface myInterface {
public String printStuff();
}
public class A implements myInterface {
#Override
public String printStuff(){
return "Stuff";
}
}
public class B implements myInterface {
#Override
public String printStuff(){
return "Stuff";
}
public String printOtherStuff(){
return "Other Stuff";
}
}
How do I call the printOtherStuff method above if I define it as follows:
public static void main(String... args) {
myInterface myinterface = new B();
String str = myinterface.printOtherStuff(); // ? This does not work
}
The above calling code does not seem work. Any ideas?
myInterface myinterface = new B();
The reference type of myinterface is myInterface. That means you can only access the methods defined in the interface. You can cast it to type B in order to make the method call.
NOTE: From here on out I'll be using the proper naming conventions.
Example
MyInterface myInterface = new B();
String str = ((B)myInterface).printOtherStuff();
Just a note on this
If you need to do this, then you need to have a look at your class design. The idea of using an interface in this way is to abstract away from the details of the object's concrete implementation. If you're having to perform an explicit cast like this, then you might want to look into either changing your interface to accommodate the necessary methods, or change your class so that the method is moved into a global location (like a util file or something).
Extra Reading
You should read about reference types here, and you should have a look at casting here. My answer is a combination of the understanding of both of these things.
As an added note, take a look at the Java Naming Conventions. This is a vital piece of information for any Java developer to make understandable code.
Surely this wouldn't work because you have reference type of Interface MyInterface. At the time of method binding compiler would try to find this method in your Interface MyInterface which is not available. So you need to cast it to your class like this.
MyInterface myInterface = new B();
B newB=(B) myInterface ;//casting to class
newB.printOtherStuff();// would work fine
change myInterface
public interface myInterface {
public String printStuff();
public String printOtherStuff();
}
If you cant change myInterface, then extends myInterface
public interface myOtherInterface extends myInterface {
public String printOtherStuff();
}
Then Implements myOtherInterface
public class B implements myOtherInterface {
#Override
public String printStuff(){
return "Stuff";
}
#Override
public String printOtherStuff(){
return "Other Stuff";
}
}
public static void main(String... args) {
myOtherInterface myotherinterface = new B();
String str = myotherinterface.printOtherStuff();
}
I am relatively new to Java and Design patterns. I am trying to implement the Builder pattern for my application. I have an interface which has a method build this build method will take the class as a parameter and return the same.
public interface TestInterface {
public TestInterface withTest(int start);
public <T> T build();
}
As of now, I have implemented this interface within a single class and overriding the methods in the GenerateBuilder class and it works fine
public class GenerateNumbers {
private String start;
private GenerateGSRN(GenerateBuilder builder) {
this.start = builder.start;
}
public static class GenerateBuilder implements TestInterface {
private String start;
#Override
public TestInterface withGcp(String start) {
this.start = start;
return this;
}
#Override
public GenerateNumbers build() {
return new GenerateNumbers(this);
}
}
}
But I want to move the GenerateBuilder class which is overriding the methods to its own separate class so that it can be used by any other class (make it as common so I do not have to write this code again).
But as we can see the GenerateBuilder Build function is tightly coupled to GenerateNumbers due to which I am unable to move it. I want to change the Build method in Interface as well as during the overriding so that it will return the instance of the class to calling class.
For example: If GenerateNumbers is calling build method then build method should return GenerateNumbers. If GenerateNumbersRandom is calling then build method should return instance of GenerateNumbersRandom.
I tried couple of things but did not work:
In interface:
public <T> T build(Class clazz);
In the override:
#Override
public <T> T build(Class clazz) {
return clazz.newInstance();
}
I hope I was able to explain the problem properly. Can someone please suggest me how to make this work.
From what I understand, you could:
declare your interface has having generic type (Builder)
declare the type you want to be built by the class implementing the interface (NumberGenerator)
declare the builder as an implementation of the interface having for generic type the class it will build (NumberGeneratorBuilder implements Builder<NumberGenerator>)
in the Builder interface, access to actual type of generic at runtime to instantiate a new instance of this type.
As an example, this would give something like:
import java.lang.reflect.ParameterizedType;
public interface Builder<T> {
default T build() throws IllegalAccessException, InstantiationException {
// in a more production-ready application, you would not reference item with their index but lookup through correct criterion to avoid getting a bad class instantiated
return ((Class<T>) ((ParameterizedType) this.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0]).newInstance();
}
}
public class NumberGenerator {
public static NumberGenerator instance() throws InstantiationException, IllegalAccessException {
return new NumberGeneratorBuilder().build();
}
// Note that visibility is important here, default constructor needs to be visible from the Builder class, and not from its implementation
NumberGenerator() {
}
public static class NumberGeneratorBuilder implements Builder<NumberGenerator> {
}
}
This might be a really stupid question, but this is the pattern that I'm interested in implementing.
Here's a basic version of the abstract class that I've implemented.
public abstract class MyCollection {
public abstract String baseUrl();
public void get(ResponseHandler handler) {
myApi.get(baseUrl(), handler);
}
}
And here's my basic static collection object
public class Users extends MyCollection {
#Override
String baseUrl() {
return "/users";
}
}
And here's what I would love to be able to do in one of my controllers
Users.get(new ResponseHandler() {
#Override
public void onSuccess(Object obj) {
//store data
}
#Override
public void onError(Object obj) {
//tell user
}
});
My problem is that Java isn't letting me access the get function inside MyCollection abstract class. Is there a way to get this pattern to work? It seems so pretty and clean to me.
You cannot invoke Users.get() because of the following reasons:
-- static methods are not inherited, even if your MyCollection class would contain a static get() method (which it doesn't contain; it contains an instance get() method, instead)
-- there is no static get() method in your Users class.
These two combined should give you a better view on why you cannot make that call.
I am trying to write some custom exceptions with helper methods for setting the variables like this:
public class KeyException extends RuntimeException {
protected String Id;
protected KeyException(String message) {
super(message);
}
protected KeyException(String message, Throwable cause) {
super(message, cause);
}
public String getId() {
return keyId;
}
public KeyException withId(final String Id) {
this.Id = Id;
return this;
}
}
However, in my derived classes, I cannot use the "withId" method as it only returns the base class - is there anyway to return the "this" pointer without having to override the method in every single derived class?
You can do something like this:
public <T extends KeyException> T withId(final String Id) {
this.Id = Id;
return (T)this;
}
Then in your derived class you just pass its type as a type parameter.
There may be a design oversight however. Apart from the builder pattern I rarely see setters return a reference to the object itself. If you would provide more context we would be able to help you more.
is there anyway to return the "this" pointer without having to override the method in every single derived class?
Yes, look at the option 1 below.
There are several ways you can do here:
Cast the result to the derived class
Override it in subclasses
Change return type to void. Since you're invoking a method on an object, you already have a pointer to it.
It's possible with generics using the following construct:
public class ParentType<T extends ParentType<T>> {
public T withId(String someId) {
/* Insert other code here */
return (T) this;
}
}
public class BranchType<T extends BranchType<T>> extends ParentType<T> {}
public final class LeafTypeA extends BranchType<LeafTypeA> {}
public final class LeafTypeB extends ParentType<LeafTypeB> {}
Where BranchType is a class with subclasses, and LeafTypeA, LeafTypeB are classes without subclasses.
This is a slight improvement over the other generics solution as it prevents:
public class LeafTypeA extends BranchType<LeafTypeB> {}
Since this does not satisfy the constraints of the type parameter.
There is one way to solve the return subclass problem using generics:
// base class
public class Base<T extends Base> {
private T myself;
public Base(T myself, Class<T> cls) {
this.myself = myself;
}
public T withSomething() {
return myself;
}
}
// subclass
public class SomeSubCls extends Base<SomeSubCls> {
public SomeSubCls() {
super(this, SomeSubCls.class);
}
}
Using this pattern new SomeSubCls().withSomething() will return the object as an instance of the subclass, rather than the parent.
Used by fest assertions for instance, check this
If you have a derived class, e.g.
public class AnotherException extends KeyException {
...
}
.... then you can simpy asign it using withId ....
AnotherException a = new AnotherException ("A");
AnotherException b = (AnotherException) a.withId("ID");
... because it's basically the same object. You just need to cast it.
unfortunately not. It would be good if you could do this
public this withId(final String Id) { // doesn't work
this.Id = Id;
return this;
}
or just
public this withId(final String Id) { // doesn't work either
this.Id = Id;
}
or it would know that "void" methods are implicitly chained (as I believe one formal proposal suggested)
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.