Spent some time pulling my hair out here. Seems black and white, but I just can't seem to get it to work. Did a lot of digging on top of what my classes have said about abstract classes in java, but to no avail.
What I'm trying to do: as part of an assignment (so no big hints please, unless it's my IDE or something), I'm making a customer class abstract, and then going ahead and making some subclasses from that. In this way the abstract class will be instantiated by creating a subclass that utilizes the abstract classes methods/properties. With me so far?
package customer;
abstract class Customer {
private String id;
private String name;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
//accessors
public double getDiscount(double amt) {
double discount = 0;
return discount;
}
public String getID() {
return this.id;
}
public String name() {
return this.name;
}
}
Abstract Customer class, seems all good, simple, easy. Now the solid subclass RetailCustomer
package customer;
public class RetailCustomer extends Customer {
private double rateOfDiscount = 0.04;
public RetailCustomer(String id, String name, double rate) {
super(id, name);
this.rateOfDiscount = rate;
}
//mutators
public void setDiscount(double rate) {
this.rateOfDiscount = rate;
}
//accessors
public double getDiscount() {
return this.rateOfDiscount;
}
}
Ok. Again, very simple. RetailCustomer extends Customer abstract class, and is supposed to make use of the abstract classes constructor, as seen with
public RetailCustomer(String id, String name, double rate) {
super(id, name);
this.rateOfDiscount = rate;
}
However my IDE (Eclipse) is showing an error "The constructor Customer(String,String) is undefined". Even though it's clearly there in the abstract class.
Note: just copying syntax from
https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html
Also as an added question (which I could most likely sort out with experimenting):
The abstract Customer class implements some methods that are just simple accessors.My understanding is that unless these are instantiated in some way by retialCustomer, the object wont instantiate as all methods need implementations?
Thank you in advance for any hints or pointers you can give. Like I said, it seems simple to me, but at the same time, getting zilch :(
Your code looks fine. Rebuild it (you may also want to have a look at IntelliJ IDEA ;) ). Also please follow convention and rename your class to RetailCustomer.
The abstract Customer class implements some methods that are just simple accessors.My understanding is that unless these are instantiated in some way by retialCustomer, the object wont instantiate as all methods need implementations?
You probably need to rephrase this, because its unclear what your asking. All subclasses will inherit the parent class' implementation. Even if your parent class is abstract, if you implement some of the methods in your class, then all the child classes will inherit those implementations. Indeed, you will still not be able to instantiate your abstract class, but you are able to use those methods from your child classes.
If you're happy with what the methods do in Customer, there is no need to override them in RetailCustomer.
What I'm trying to do: as part of an assignment (so no big hints please, unless it's my IDE or something)
+1.
Related
I´ve got a question about inheritance/force certain value to an attribute in Java I am not sure about, even I spend a lot of time thinking about it. I will try to be as simple as possible.
So I´ve got an abstract class Foo, which has the Lombok annotation #Data:
#Data
public abstract class Foo{
private String id;
protected BoundType type;
public abstract void setBoundType(BoundType boundType);
}
Here is the enum BoundType:
public enum BoundType {
IN, OUT;
}
And I´ve got another two classes, InFoo and OutFoo that extend Foo. The boundType of InFoo should always be the enum type IN. On the other side, the boundType in OutFoo should always be the enum type OUT. For instance:
#Data
public class InFoo extends Foo{
public void setBoundType() {
//ALWAYS HAS TO BE BoundType.IN
}
}
How can I enforce this? Not sure how to design it. Thanks in advance.
Make sure the constructor sets the correct value for each subclass, and then make sure there's no setter, so that there's no way to alter the value.
Also, see this post Omitting one Setter/Getter in Lombok on how to omit the setter for the BoundType field.
The correct value should be set in the constructor of the subclasses:
public InFoo() {
boundType = BoundType.IN;
}
If it is necessary to use the setter pattern, you can perform a check, there:
public void setBoundType(BoundType boundType) {
if(boundType != BoundType.IN)
throw new IllegalArgumentException();
this.boundType = boundType; // This line is actually unnecessary
}
In my app, I am using realm as a database platform. Realm has been great thus far- super easy to use, make queries, etc.-though, I have two qualms with it that I am trying to work around.
1) Realm does not support inheritance in model object classes which extend RealmObject.
- I am wondering if any developers out there have used composition as a workaround to the inheritance issue and if its worked for them.
- In other words, say I have a class "car" which extends RealmObject and then I have other classes such as "honda", "toyota", etc. Does it make sense to make separate car objects for each of these which contain either a honda, toyota, etc.?
2) Realm only supports getters and setters in model object classes
- My current workaround for this is by creating static methods within the model object classes.
- In other words, say I want to modify a honda's color, I would call something such as, Honda.updateColor(honda, blue).
- ^ Is this sloppy, or is this essentially the only way to handle such methods.
Really any feedback would be great!
A workaround I've used (in a nutshell)
Composition + Interface inheritance would allow you to get some polymorphism benefits back to your realmObjects.
Some code demonstration
interface IPerson {
String getName();
}
class Person extends RealmObject implements IPerson {
String name;
#Override
public String getName() {
return name;
}
}
interface IWorker extends IPerson {
int getSalary();
}
class Worker extends RealmObject implements IWorker {
Person person;
int salary;
#Override
public String getName() {
return person.getName();
}
#Override
public int getSalary() {
return salary;
}
}
Note
PrimaryKeys unfortunately have to be duplicated.
Check this answer of mine to get more details about this workaround.
'Making the class field/property private' - is one of the best practice in OOP. To access the private field/property we can use public getter method. But only writing the getter method may not enough according to this blog(Please see Quote 2). It suggests returning a clone of the field/property (if it is a reference type) from the getter method. By following this approach we can make the field/property unmodifiable. Please see the code below -
public class Department{
Employee admin;
...
...
...
public Employee getAdmin(){
return admin.clone();
}
}
So from now the 'admin' is unmodifiable by the outer world if we don't use any setter. This approach looks pretty nice. But I hardly found any code which implements this approach. Is there any drawbacks of using this approach which may defeats the benefit of using this approach?
Thanks in advance.
The main drawback to this approach is the need to make a clone every time you get an object, which is not ideal, because ideally you prefer your getter to be lightweight.
There are two approaches that achieve similar effect without cloning:
Making Employee immutable, and
Giving Employee an immutable interface
The first approach is self-explanatory and is very efficient, but it is not always practical, especially in situations when your object represents state that needs to be shared in place.
The second approach is simple, too: rather than making Employee a class, make it an interface with only getters, make a class EmployeeImpl that implements Employee, and has getters and setters, and use the class when you need mutability.
public interface Employee {
String getFirstName();
String getLastName();
}
public class EmployeeImpl implements Employee {
private String firstName;
private String lastName;
public String getFirstName() {return firstName;}
public String getLastName() {return lastName;}
public void setFirstName(String name) {firstName = name;}
public void setLastName(String name) {lastName = name;}
}
This approach can be defeated by casting to a class, but most of the time it is OK.
If you are in a hostile environment where any modification to the actual object would be extremely harmful - say, you are exposing some API for your service that everyone could download and use, you would have to go for the full clone approach that you have described. However, situations like this are relatively rare.
Note: I changed this answer since it was first posted. The first solution I suggested had problems with inheritance which are now solved.
Cloning the objects returned is, generally, a very bad option. Unless the objects are very simple, or unless your application is not very complex, all this cloning will very likely introduce a significant overhead.
An alternative for your specific case is to have an interface called Employee that only offers getters. You can then also define the MutableEmployee class that implements Employee and also offers setters.
interface Employee {
public String getName();
public float getSalary();
}
class MutableEmployee implements Employee {
private String name;
private float salary;
#Override
public String getName() {
return name;
}
#Override
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
super.salary = salary;
}
public void setName(String name) {
super.name = name;
}
}
Your Department class would then modified like this:
class Department {
private MutableEmployee admin;
public Employee getAdmin() {
return (Employee) admin;
}
public MutableEmployee getMutableAdmin() {
return admin;
}
}
Defining subclasses of MutableEmployee
When you want to create a subclass of MutableEmployee, like MutableGraphicDesigner, you will need to define the following:
interface GraphicDesigner extends Employee
class MutableGraphicDesigner extends MutableEmployee implements GraphicDesigner
Ok I have an abstract class 'Order':
public abstract class Order {
protected String location;
protected double price;
public Order(double price, String location){
this.price = price;
this.location = location;
}
public abstract double calculateBill();
public String getLocation() {
return location;
}
public double getPrice() {
return price;
}
public abstract String printOrder(String format);
}
I also have 3 classes that implement it that are similar except, of course, that they calculateBill differently according to tax, tariff, etc.
now I am trying to create and OrderManager class to manage them. This is what I have so far
public class OrderManager {
private ArrayList<Order> orders;
public OrderManager() {
}
public OrderManager(ArrayList<Order> orders) {
this.orders = orders;
}
public void addOrder(Order o) {
orders.add(o);
}
public ArrayList<Order> getOrdersAbove(double val) {
for (Order o : orders) {
double bill = o.calculateBill();
if (bill > val)
orders.add(o);
}
return orders;
}
I'm having trouble with the getOrdersAbove method which should return and array list of orders whose bill is above val. Being the calculateBill is abstract and implemented in each subclass of order I should just be able to call it correct? Also if that is the case then shouldn't OrderManager extend Order? Or just being in the same package would allow me to call it's methods? Or am I going about it all wrong?
Thanks for any and all help!
Being the calculateBill is abstract and implemented in each subclass
of order I should just be able to call it correct?
The method is declared as public, you will be able to call it on Order instances.
Also if that is the case then shouldn't OrderManager extend Order?
Ask yourself: is an OrderManager an Order? No? So don't make it extend Order.
Or just being in the same package would allow me to call it's methods?
Again, the method is public, so you can call it from anywhere as long as you have an instance to call it on.
So in your for loop
public ArrayList<Order> getOrdersAbove(double val) {
for (Order o : orders) {
double bill = o.calculateBill();
// do logic
}
}
When calling calculateBill(), Java will use late-binding (polymorphism) to resolve the actual implementation of the method to use.
Your OrderManager doesn't need to know anything about the calculateBill method of subclasses of Order.
As long as the method is overriden you can be sure that you will be allowed to invoke it if it's public (or they're in same package) since you can't reduce the visibility of an inherited method.
Even if Order is abstract and calculateBill is abstract in that class that doesn't forbid you from calling the method. The only restriction which is applied to abstract classes is that you can't instantiate them, once you have an instance (even if its runtime type is narrower) then you shouldn't worry about anything.
Being the calculateBill is abstract and implemented in each subclass of order I should just be able to call it correct?
Java Runtime doesn't really care that there's no implementation of the calculateBill() method in Order, just that Order "knows about" (or maybe better yet, "has declared") a method called calculateBill() which accepts no arguments and returns a double -- which it does because of your line:
public abstract double calculateBill();
Ensuring that concrete subclasses actually implement the abstract method is a check done at compile time. As long as you've overridden the calculateBill() methods in the subclasses (which you would need to do for the code to compile), you'll be able to call it (from anywhere, since you declared it as public). The specific implementation calculateBill() -- that is whether it's class Foo's implementation or class Bar's -- will be selected for you at runtime, based on the specific subclass instance you're calling it on.
Also if that is the case then shouldn't OrderManager extend Order?
No. I don't see why it should. It doesn't seem to make a ton of sense. If you did, you'd have to have a concrete implementation of calculateBill() inside OrderManager which similarly doesn't seem to make a ton of sense.
Or just being in the same package would allow me to call it's methods?
Public (nonstatic) methods (which calculateBill() is) are callable by anyone who has an instance of the class, whether the calling class is within the same package or not.
Or am I going about it all wrong?
You seem to be on the right track with abstract methods and implementations in the subclasses, as well as providing default implementations of various methods in the abstract class (e.g. getPrice(), getLocation())
getOrdersAbove should create a new ArrayList to hold the orders above val.
You are adding the selected orders back to the list you are iterating over which will cause the iterator to fail.
Why do we need constructors and private members in the abstract class? It is not like we are ever going to create an instance of that class.
You will create instances, just instances of a derived class. Those derived classes will still need to call constructors, and can still call members of the abstract class - which may in turn use private members.
Here's an example (not a terribly useful one, but just to show the basic idea...)
public abstract class NamedObject
{
private final String name = name;
protected NamedObject(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
public class Computer extends NamedObject
{
private final int processorSpeed;
public Computer(String name, int processorSpeed)
{
super(name); // See, the constructor is useful
this.processorSpeed = processorSpeed;
}
public String toString()
{
return getName() + " (" + processorSpeed + ")";
}
}
I can't say I write abstract classes that often, generally preferring composition to inheritance, but when I do create them I certainly use constructors and private members.
Abstract classes provide a partial implementation of some interface. It's perfectly reasonable to consider that you might want to provide part of that implementation and disallow client code (concrete subclasses) from accessing the specifics - i.e. an extension of the principle of encapsulation.
Marking some members as private forces the inheriting class to call protected methods to access that partial implementation; providing a constructor allows for subclasses to initialise the parent's encapsulated state during their own construction.
Unlike an interface, an abstract class that defines data fields is in fact instantiated in the sense that these data fields are allocated. It is just that they are never instantiated on their own, they are instantiated as part of something bigger - the subclass. So when the subclass is built, the supertype is built as well, which is why you would need a constructor.
Depending on your hierarchy, your abstract class may have a meaning and state. For example, if your application is a school you may have the notion of a person (that has a name and an SSN), but you would have different subtypes for students and for faculty. Because both types of people share certain state structure (name and SSN) you would have both classes extend the Person class. But you would never simply instantiate a person directly.
In addition to Jon's answer, I'd like to mention that abstract classes still go well with composition, if you keep the subclass tree shallow. I.e. it is great for providing a common base class for a few closely related objects, but not for creating a gigantic tree of subclasses.
Why do you need private class? I think that you are confusing abstract classes with interfaces. Unlike interfaces, abstract classes can hold functionality. For example:
public class AbstractBase{
private int num;
public AbstractBase(int number){
this->num = number;
}
public int method(){
return ( this->num * this->templateMethod());
}
public abstract int templateMethod();
}
public class ConcreteDerived extends AbstractBase{
public ConcreteDerived(){
super(4);
}
public int templateMethod(){
return number; //number is the result of some calculation
}
}
In this example, you´ll never explicitly instantiate AbstractBase, but by declaring members and constructors, you can customize the functionality of your classes (this is called template method).
Assuming you're doing ad hoc code or prototyping, you do instantiate abstract classes (or maybe even interfaces) from time to time. They're called anonymous inner classes (one, two) and look like this:
// you have this...
public abstract class SomeClass {
public abstract String returnAString();
}
// ...and this...
public class OtherClass {
public void operate(SomeClass c) {
System.out.println(c.returnAString());
}
}
// ...so you do this:
OtherClass oc = new OtherClass();
// this is one of the reasons why you need to specify a constructor
oc.operate(new SomeClass() {
#Override
public String returnAString() {
return "I'm an anonymous inner class!";
}
});
This example is of course quite redundant but should expose the point. Some existing frameworks even rely on the heavy usage of this behaviour, namely Apache Wicket at least.