I have following requirements:
I have few vehicles (implementing SingleVehicle
) and those can be SingleCar
, SingleMotorcycle
and SingleTruck
. There can be only single instance of a vehicle at a given time. CarPlant
is producing vehicles, and saves those in producedVehicles
map. Special type of vehicle is SingleTruck
, since it has to have loaded at least one car or motorcycle. If SingleMotorcycle
is produced, then it will load that one - otherwise it will take produced SingleCar
and load that one. CarPlant
implements observable interface in order to notify truck in case that SingleMotorcycle
is produced - so truck can load that one. SingleTruck
implements NotifiableVehicle
in order to be able to receive notification from CarPlant
.
Here is the code:
class Program{
public static void main(String[] args) {
CarPlant plant = new CarPlant();
plant.produce(SingleVehicle.Name.SINGLE_CAR);
plant.drive(SingleVehicle.Name.SINGLE_CAR,123);
plant.produce(SingleVehicle.Name.SINGLE_TRUCK);
plant.drive(SingleVehicle.Name.SINGLE_TRUCK,456);
plant.produce(SingleVehicle.Name.SINGLE_MOTORCYCLE);
plant.drive(SingleVehicle.Name.SINGLE_TRUCK,789);
}
}
class CarPlant implements Observable{
SingleVehicle lastAdded;
Set<NotifiableVehicle> observers = new HashSet<>();
NavigableMap<SingleVehicle.Name, SingleVehicle> producedVehicles = new TreeMap<>();
VehicleFactory factory = name -> switch (name) {
case SINGLE_CAR -> new SingleCar();
case SINGLE_MOTORCYCLE -> new SingleMotorcycle();
case SINGLE_TRUCK -> {
//should this logic be here, since it is accessing outer producedVehicles?
SingleTruck truck;
if (producedVehicles.containsKey(SingleVehicle.Name.SINGLE_MOTORCYCLE)) {
truck = new SingleTruck(producedVehicles.get(SingleVehicle.Name.SINGLE_MOTORCYCLE), CarPlant.this);
} else {
truck = new SingleTruck(producedVehicles.get(SingleVehicle.Name.SINGLE_CAR), CarPlant.this);
}
yield truck;
}
};
void produce(SingleVehicle.Name name){
lastAdded = factory.getVehicle(name);
producedVehicles.put(name, lastAdded);
//notify observers that something changed
//should I always notify, or should I have here filter -> if motorcycle or car then notify?
observers.forEach(o -> o.notifyMe());
}
void drive(SingleVehicle.Name name, Integer speed){
producedVehicles.get(name).drive(speed);
}
@Override
public SingleVehicle getLastAdded() {
return lastAdded;
}
@Override
public void addObserver(NotifiableVehicle notifiable) {
observers.add(notifiable);
}
}
interface VehicleFactory{
SingleVehicle getVehicle(SingleVehicle.Name name);
}
interface Drivable{
void drive(Integer speed);
}
abstract class SingleVehicle implements Drivable{
enum Name{
SINGLE_CAR,
SINGLE_MOTORCYCLE,
SINGLE_TRUCK
}
@Override
public void drive(Integer speed) {
System.out.println("Drive " + this.getClass().getName() + " at speed " + speed);
}
}
interface NotifiableVehicle{
void notifyMe();
}
interface Observable{
SingleVehicle getLastAdded();
void addObserver(NotifiableVehicle notifiable);
}
class SingleCar extends SingleVehicle{}
class SingleMotorcycle extends SingleVehicle{}
class SingleTruck extends SingleVehicle implements NotifiableVehicle {
SingleVehicle loadedVehicle;
Observable observable;
SingleTruck(SingleVehicle toCarry, Observable observable){
loadedVehicle = toCarry;
this.observable = observable;
//should I register observer here? I need reference anyway
//but I think it is bad that "this" escapes before constructor is done?
observable.addObserver(this);
}
@Override
public void drive(Integer speed) {
super.drive(speed);
System.out.println(" ----> but having inside " + loadedVehicle.getClass().getName());
}
@Override
public void notifyMe() {
if(observable.getLastAdded() instanceof SingleCar || observable.getLastAdded() instanceof SingleMotorcycle) {
loadedVehicle = observable.getLastAdded();
}
}
}
Questions are:
- I saw that using static factory, it is implemented using
String
s. Why is this the case, and what is advantage of this over using enums as inVehicleFactory factory = name -> switch (name) {...
. - Is there any other best-practice, than using
SingleVehicle.Name.SINGLE_CAR
andclass SingleCar
? Seems that I always have to create enum for each vehicle class that I create. What comes up to my mind is usingString
s, but then I loose type safety. Or usingClass<? extends SingleVehicle>
- but not sure how much is this user friendly. - Should the factory (
VehicleFactory factory
) has a reference to outerproducedVehicles
, in order to decide which argument to pass toSingleTruck
when initializing it? - Should observer be registered inside
SingleTruck
(as is now), or insideVehicleFactory factory
(after creation)? - Should I create that
enum Name
insideSingleVehicle
, sinceSingleVehicle
is more abstract, and whenever I add new Vehicle, I would need to modify that enum and recompileSingleVehicle
without any reason.
Aucun commentaire:
Enregistrer un commentaire