Reputation: 23322
In my Java program, I have two classes that are really similar, and it would make a lot of sense to create a superclass for them to subclass and generalize a bunch of their methods.
The only problem is that one of their key fields is implemented in one as a Queue
and in one as a PriorityQueue
.
Is there any way to superclass these and somehow generalize the field type and let the subclasses pick what it will perhaps on instantiation?
public Base{
}
public Sub1{
Queue<Customer> customers;
}
public Sub2{
PriorityQueue<Customer> customers;
}
Upvotes: 1
Views: 408
Reputation: 15212
What you need to do is have the queue of customers
as a dependency in Base
and let the client code decide what queue to instantiate.
public Base{
private Queue<Customer> customers;
protected Base(Queue<Customer> customers) {
this.queue = queue;
}
}
You don't need the Sub1
and Sub2
classes since they only differ from Base
in terms of the queue used. Client code can simply decide what queue to use :
Base baseWithQueue = new Base(new ArrayBlockingQueue<Customer>());
Base baseWithPriorityQueue = new Base(new PriorirityQueue<Customer>());
Upvotes: 1
Reputation: 2613
One solution is to give your customers
attribute the general Queue
type, which will give you flexibility. But if you want to enforce specific implementations in a given subclass, and carry that information in the rest of your program, you can use generic constraints :
public class Base<Q extends Queue<Customers>> {
protected Q customers;
public Base(Q customers) {
this.customers = customers;
}
}
public Sub1 extends Base<Queue<Customers>> {
public Sub1(Queue<String> customers) {
super(customers);
}
}
public Sub2 extends Base<PriorityQueue<Customers>>{
public Sub2() {
// Sub2 only supports PriorityQueues
super(new PriorityQueue<String>());
}
}
This can be useful, as it allows you to call, say, customers.comparator()
inside Sub2
without having to cast customers
into a PriorityQueue
.
Upvotes: 1
Reputation: 1074248
Yes, since PriorityQueue
implements Queue
. If you want to delegate creation to subclasses, have them pass the appropriate Queue
to use to the base constructor:
public class Base {
protected final Queue<Customer> customers;
protected Base(Queue<Customer> c) {
this.customers = c;
}
}
public class Sub1 extends Base {
Sub1() {
super(new WhateverQueue<Customer>());
}
}
public class Sub2 extends Base {
Sub2() {
super(new PriorityQueue<Customer>());
}
}
I should mention that if Sub2
needs to use methods that are specific to PriorityQueue
(such as comparator
) in some Sub2
-specific method, it can either:
Cast customers
(since it knows that customers
is actually a PriorityQueue<Customer>
, not just a Queue<Customer>
), or
Declare its own instance field which will keep the typed reference:
private PriorityQueue<Customer> priorityCustomers;
Sub2() {
super(new PriorityQueue<Customer>());
this.priorityCustomers = (PriorityQueue<Customer>)(this.customers);
}
#2 keeps the casting required to a minimum and nicely contained to just the constructor, making it easier to change PriorityQueue<Customer>
to something else later.
Upvotes: 1
Reputation: 5647
Yes, if you implement the field as Queue
, you can instantiate the field as a PriorityQueue
in Sub2
, because PriorityQueue
implements Queue
(source: http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html)
public Base{
Queue<Customer> customers;
public Base(Queue<Customers> queue){
this.customers = queue;
}
}
public Sub1{
public Sub1(){
super(new Queue<Customer>());
}
}
public Sub2{
public Sub2(){
super(new PriorityQueue<Customer>());
}
}
However, when you need to use the customers
field as a PriorityQueue
(rather than a Queue
) inside Sub2
, you will need to cast it to a PriorityQueue
.
Upvotes: 1
Reputation: 3962
The PriorityQueue
class implements the Queue
interface, so I'd recommend making Base
an abstract class and keep the customers
collection (of type Queue
) in there. Then instantiate customers
from Sub1
or Sub2
's constructor as appropriate.
Upvotes: 1
Reputation: 494
priorityqueue is a subclass of abstract queue which implements queue, so basically base could have a queue of customers.
Upvotes: 1