I'm attempting this question in preparation for a test. This is my best answer based on my understanding but I feel I may be missing something important. I think I have altered the responsibility of Navigator too much but I can't see a better way of doing it.
The question is:
public class Navigator
{
private Route theRoute;
public Navigator(UserInterface ui) {
String destination = ui.getDestEntry().getText();
theRoute = new Route(GPS.getLocation(), destination);
theRoute.calculateRoute();
}
public void display() {
MapView theMap = new MapView();
theMap.plot(theRoute);
}
}
public class GPS {
public static String getLocation() { ... }
}
“{ ... }” stands for an algorithm that we do not need to examine, for our purposes.
Refactor the Navigator and GPS classes to conform to the Dependency Injection pattern. Do not alter their basic responsibilities.
(a) Your refactored Navigator and GPS classes: (You will have more space on the
real test.)
(b) The injector code (just as a sequence of statements)
My answers:
(a)
public class Navigator {
private Route theRoute;
private MapView theMap;
public Navigator (Route inRoute) {
theRoute = inRoute;
theRoute.calculateRoute();
}
public void display(MapView inMap) {
theMap = inMap;
theMap.plot(theRoute);
}
}
public class GPS {
public GPS(); //constructor
public String getLocation(){...}
}
(b)
Injector code:
UserInterface ui = new UserInterface;
String destination = new String(ui.getDestEntry().getText());
GPS gps = new GPS;
Route theRoute = new Route (GPS.getLocation(), destination);
new Navigator(theRoute);
Could be better.
public class Navigator {
private final Route theRoute;
private final MapView theMap;
public Navigator(Route inRoute, MapView theMap) {
theRoute = inRoute;
this.theMap = theMap;
}
public void setup() {
theRoute.calculateRoute();
}
public void display() {
theMap.plot(theRoute);
}
}
b) Your injector code is incomplete or wrong
The Navigator has dependency to GPS, so you need to add property to the navigator
public class Navigator
{
private GPS gps;
private UserInterface ui;
public Navigator(UserInterface ui, GPS gps) {
this.ui = ui;
this.gps = gps;
}
public void display() {
String destination = ui.getDestEntry().getText();
Route theRoute = new Route(gps.getLocation(), destination);
theRoute.calculateRoute();
MapView theMap = new MapView();
theMap.plot(theRoute);
}
}
public class GPS {
public String getLocation() { ... }
}
My c# refactored variant looks like:
public class ClientCode
{
void DoNavigations(IDestinationEntry ui, IGPS gps)
{
String destination = ui.getDestEntry().getText();
IRoute theRoute = new Route(gps.getLocation(), destination);
INavigator nv = new Navigator(theRoute);
nv.display();
}
}
public class Navigator : INavigator
{
private IRoute _theRoute;
public Navigator(IRoute theRoute)
{
_theRoute = theRoute;
_theRoute.calculateRoute();
}
public void display()
{
MapView theMap = new MapView();
theMap.plot(_theRoute);
}
}
public interface IGPS
{
string getLocation();
}
public interface INavigator
{
void display();
}
public interface IDestinationEntry
{
DestinationEntry getDestEntry();
}
public interface IRoute
{
void calculateRoute();
}
Related
Finally I solve problem by myself
It turns out that consumers can transform
and Through the interface let my xxx_dialogs and Compulsory use openDialog function.
Data bean start for product, Customer
public class Prod extends MyBean {
private String P_NO = "";
private setP_NO(String p_no){
P_NO= p_no;
}
private String getP_NO(){
return P_NO;
}
}
public class Cust extends MyBean {
private String CUST_NO = "";
....
}
public class MyView{
TextField textFieldP_NO;
Button btnProd;
Button btnCust;
public MyView (){
//...constructor...
}
btnProd.addClickListener(e -> {
Prod_Dialog p_dlg = new Prod_Dialog();
//fix before
//p_dlg.openDialog(p -> textFieldP_NO.setValue(p.getP_NO()));
//fix after
p_dlg.openDialog(p -> textFieldP_NO.setValue(((PROD_Dialog.Prod) p).getP_NO()));
});
btnCust.addClickListener(e -> {
Cust_Dialog c_dlg = new Cust_Dialog();
//fix before
//c_dlg.openDialog(c -> textFieldP_NO.setValue(c.getCUST_NO()));
//fix after
c_dlg.openDialog(c -> textFieldP_NO.setValue(((CUST_Dialog.Cust) c).getCUST_NO()));
});
}
[Interface] fix parametere Consumer can Polymorphism
public interface BaseDialog {
//fix before just for prodct. That's bad....
//public abstract void openDialog(Consumer<Prod> selectionAction);
//fix after that can service any MyBean...
public abstract void openDialog(Consumer<? extends MyBean> selectionAction);
}
[Dialog] with Prod_Dialog and cust_Dialog thougth clickok method pass Consumer<Prod> or Consumer<Cust>
//fix before
//public class Prod_Dialog {
//fix after
public class Prod_Dialog implements BaseDialog{
private Button btnOk;
...
//fix before
//public void openDialog(Consumer<Prod> selectionAction) {
//fix after
public void openDialog(Consumer<? extends MyBean> selectionAction) {
btnOk.addClickListener(e -> {
//fix before
// Prod sel_prod = grid.asSingleSelect().getValue();
// String p_no = sel_prod.getP_NO(); //get user selected p_no
// Prod prod = new Prod();
// prod.setP_NO(p_no);
// selectionAction.accept(prod);
//fix after that is magic point for me, by Consumer Transformation
clickOK((Consumer<Prod>) selectionAction);
}
}
public void clickOK(Consumer<Prod> selectionAction) {
Prod sel_prod = grid.asSingleSelect().getValue();
String p_no = sel_prod.getP_NO(); //get user selected p_no
Prod prod = new Prod();
prod.setP_NO(p_no);
selectionAction.accept(prod);
}
}
public class Cust_Dialog implements BaseDialog{
private Button btnOk;
...
public void openDialog(Consumer<? extends MyBean> selectionAction) {
btnOk.addClickListener(e -> {
//fix before
// Cust sel_cust = grid.asSingleSelect().getValue();
// String c_no = sel_cust.getCUST_NO(); //get user selected p_no
// Cust cust = new Cust();
// Cust.setCUST_NO(c_no);
// selectionAction.accept(cust);
//fix after
clickOK((Consumer<Cust>) selectionAction); //that is magic point for me, by Consumer Transformation
}
}
public void clickOK(Consumer<Cust> selectionAction) {
Prod sel_cust = grid.asSingleSelect().getValue();
String c_no = sel_prod.getCUST_NO(); //get user selected p_no
Cust cust = new Cust();
cust.setCUST_NO(c_no);
selectionAction.accept(cust); //that is magic point for me
}
}
Your working implementing class code method signature
public void openDialog(Consumer<PROD> selectionAction)
is not identical to the interface signature
public abstract void openDialog(Consumer<? extends MyBean> selectionAction);
Do not write abstract in the interface signature declaration (they are public and abstract by default)!
Arguments to the methods will / must / are - always be identical too!
Implementing class code method signature should be almost and if not , totally identical in the interface.
I want to execute commands for each product view. Consider 10 products views, and each of them can execute the PrintProductViewCommand. This command, takes in constructor a ProductView and prints its name. Since it is #Injectable, the container will create a new ProductView each time the command is created. The following example shows what I want to do:
public class InjectionTest {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(ProductView.class);
bind(CommandExecutor.class);
bind(PrintProductViewNameCommand.class);
install(new FactoryModuleBuilder().implement(ProductView.class, ProductView.class)
.build(ProductViewFactory.class));
}
});
List<ProductView> productViews = new ArrayList<>();
ProductViewFactory factory = injector.getInstance(ProductViewFactory.class);
for (int i = 0; i < 10; i++) {
productViews.add(factory.create("Name: " + String.valueOf(i)));
}
System.out.println("Done creating");
//Now sometime in future, each product view calls print method
productViews.forEach(ProductView::print);
}
private static interface ProductViewFactory {
ProductView create(String name);
}
private static class ProductView {
private String name; //simulate a property
private CommandExecutor executor;
public ProductView() {
//Guice throws exception when this is missing
//Probably because it is being asked in PrintProductViewCommand
}
#AssistedInject
public ProductView(#Assisted String name, CommandExecutor executor) {
this.name = name;
this.executor = executor;
}
public String getName() {
return name;
}
//assume some time product view it self calls this method
public void print() {
executor.execute(PrintProductViewNameCommand.class);
}
}
#Singleton
private static class CommandExecutor {
#Inject
private Injector injector;
public void execute(Class<? extends Command> cmdType) {
injector.getInstance(cmdType).execute();
}
}
private static class PrintProductViewNameCommand implements Command {
private ProductView view;
#Inject
public PrintProductViewNameCommand(ProductView view) {
this.view = view;
}
#Override
public void execute() {
//Want to print "Name: something" here
System.out.println(view.getName());
}
}
private static interface Command {
void execute();
}
}
This problem is solved if I add a parameter to Command interface, and make it Command<T>. Then CommandExecutor will have this method:
public <T> void execute(Class<? extends Command<T>> cmdType, T parameter) {
injector.getInstance(cmdType).execute(parameter);
}
So, my PrintProductViewNameCommand is now class PrintProductViewNameCommand implements Command<ProductView>, and in product view :
public void print() {
executor.execute(PrintProductViewNameCommand.class,this);
}
However, the Command Pattern has no parameter in execute(). I have also seen somewhere that adding a parameter is an anti-pattern.
Of course, the command is simple. Assume that the command has other dependencies too, like Services etc.
Is there a way I can achieve it? Perhaps I am doing something wrong, probably with the whole DI situation.
When not using dependency injection, I would do something like this:
ProductView view = new ProductView();
Command command = new PrintProductViewNameCommand(view);
view.setPrintCommand(command);
But how to it while using DI?
So this works, although I'm not sure if it's 100% what you want to do.
public class InjectionTest {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(CommandExecutor.class);
bind(ProductView.class);
install(new FactoryModuleBuilder()
.implement(ProductView.class, ProductView.class)
.build(ProductViewFactory.class));
install(new FactoryModuleBuilder()
.implement(PrintProductViewNameCommand.class, PrintProductViewNameCommand.class)
.build(PrintProductViewNameCommand.Factory.class));
}
});
ProductViewFactory factory = injector.getInstance(ProductViewFactory.class);
List<ProductView> productViews = new ArrayList<>();
for (int i = 0; i < 10; i++) {
productViews.add(factory.create("Name: " + i));
}
System.out.println("Done creating");
//Now sometime in future, each product view calls print method
productViews.forEach(ProductView::print);
}
private interface ProductViewFactory {
ProductView create(String name);
}
private static class ProductView {
private String name;
private CommandExecutor executor;
private PrintProductViewNameCommand printProductViewNameCommand;
#AssistedInject
public ProductView(#Assisted String name, PrintProductViewNameCommand.Factory printProductViewNameCommandFactory, CommandExecutor executor) {
this.name = name;
this.executor = executor;
this.printProductViewNameCommand = printProductViewNameCommandFactory.create(this);
}
public ProductView() {}
public String getName() {
return name;
}
//assume some time product view it self calls this method
public void print() {
executor.execute(printProductViewNameCommand);
}
}
#Singleton
private static class CommandExecutor {
public void execute(Command command) {
command.execute();
}
}
private static class PrintProductViewNameCommand implements Command {
private final ProductView view;
#AssistedInject
public PrintProductViewNameCommand(#Assisted ProductView view) {
this.view = view;
}
static interface Factory {
PrintProductViewNameCommand create(ProductView productView);
}
#Override
public void execute() {
//Want to print "Name: something" here
System.out.println(view.getName());
}
}
private static interface Command {
void execute();
}
}
Basically what you're running into is a cyclic dependency problem (https://github.com/google/guice/wiki/CyclicDependencies#use-factory-methods-to-tie-two-objects-together) that's also exasperated by a bit by the fact that you have an additional AssistedInject in the ProductView.
By the way I'm using Guice 3 in this example.
I am implementing a command pattern in android.
This is what I have right now. For some reason this does not run. It is like the AddUserRequest is getting garbage collected for some reason.
RequestManager.java:
public class RequestManager extends BroadcastReceiver {
private static final RequestManager instance = new RequestManager();
private boolean isConnected = false;
private static ArrayList<Request> requestQueue = new ArrayList<Request>();
private RequestManager() {
}
/* singleton class */
public static RequestManager getInstance() {
return instance;
}
public void invokeRequest(Request request) {
request.execute(); // only to test this, this will change
return;
}
}
AddUserRequest.java
public class AddUserRequest extends InsertionRequest {
User user;
public AddUserRequest(User user) {
this.user = user;
}
public void execute() {
System.out.println("TEST!!!");
}
}
Request.java:
public abstract class Request {
public abstract void execute();
}
}
InsertionRequest.java
public abstract class InsertionRequest extends Request {
}
RequestManagerTest.java
public class RequestManagerTest extends ActivityInstrumentationTestCase2 {
public RequestManagerTest(){
super(MainActivity.class);
}
public void testAddUserRequest() {
User user = new User();
user.setName("Tester12345");
AddUserRequest request = new AddUserRequest(user);
RequestManager.getInstance().invokeRequest(request);
}
}
For some reason this does not print "TEST!!!" and for the life of me I cannot figure out why. I looked in the debug log and everytime request.execute() in RequestManager.java gets called there is a "GC Explicit..." which I suspect has to do with garbage collection. What is the proper way to do what I am trying to do?
I believe I've seen variants of this question, but no "definitive answer". In the code below, I understand that SomeEventManager holds a reference to someImplClassTwo.myEventListenerA and someImplClassTwo.myEventListenerB, and that this does not allow for someImplClassTwo to be garbage collected, and this results in the output generated the second time someEventManager.notifyListeners() is invoked.
But, I'd really like for users of SomeImplClass not to have to know that there are listeners involved in the implementation, and that these listeners need to be manually un-registered (i.e., SomeImplClass.releaseListeners()) before releasing the SomeImplClass object.
Is there a clean/accepted way of doing this?
p.s. I've already played with finalize(), just for fun, and confirmed that GC is not even attempted in this case, for either instance of SomeImplClass. So, that seems to be a non-starter as a potential solution.
Test Driver
public class TestDriver {
public static void main(String[] args) {
SomeEventManager someEventManager = SomeEventManager.getInstance();
SomeImplClass someImplClassOne = new SomeImplClass("One");
SomeImplClass someImplClassTwo = new SomeImplClass("Two");
someEventManager.notifyListeners();
someImplClassOne.releaseListeners();
someImplClassOne = null;
someImplClassTwo = null;
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
someEventManager.notifyListeners();
}
}
Event Interface
public interface SomeEventListener {
public void handleSomeEvent();
}
Event Manager
import java.util.ArrayList;
import java.util.List;
public class SomeEventManager {
private static SomeEventManager eventManager = null;
private List<SomeEventListener> listeners = null;
private SomeEventManager() {
listeners = new ArrayList<SomeEventListener>();
}
public static SomeEventManager getInstance() {
if (eventManager == null) {
eventManager = new SomeEventManager();
}
return eventManager;
}
public void addListener(SomeEventListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void removeListener(SomeEventListener listener) {
listeners.remove(listener);
}
public void notifyListeners() {
for(SomeEventListener listener : listeners) {
listener.handleSomeEvent();
}
}
}
Event Listener Implementation
public class SomeImplClass {
private InnerEventListener myEventListenerA = null;
private InnerEventListener myEventListenerB = null;
private String id = null;
public SomeImplClass(String id) {
this.id = id;
myEventListenerA = new InnerEventListener(id + "_A");
myEventListenerB = new InnerEventListener(id + "_B");
}
public void releaseListeners() {
myEventListenerA.unregisterListener();
myEventListenerB.unregisterListener();
}
private class InnerEventListener implements SomeEventListener {
private SomeEventManager someEventManager = null;
private String id = null;
public InnerEventListener(String id) {
someEventManager = SomeEventManager.getInstance();
this.id = id;
registerListener();
}
public void registerListener() {
someEventManager.addListener(this);
}
public void unregisterListener() {
someEventManager.removeListener(this);
}
public void handleSomeEvent() {
System.out.println("InnerEventListener->" + id);
}
}
}
The solution we use is to have the listener automatically unregister itself if it gets called and the thing it's updating has been collected.
It looks a bit like this:
private static class InnerEventListener implements SomeEventListener {
private final WeakReference<ThingToUpdate> thingRef;
public InnerEventListener(ThingToUpdate thing) {
thingRef = new WeakReference<>(thing);
}
#Override
public void handleSomeEvent(SomeEvent event) {
ThingToUpdate thing = thingRef.get();
if (thing != null) {
thing.updateSomehow();
} else {
((SomeEventedThing) event.getSource())
.removeSomeEventListener(this);
}
}
}
//...
SomeEventedThing eventedThing;
ThingToUpdate thingToUpdate;
//...
eventedThing.addListener(new InnerEventListener(thingToUpdate));
I wouldn't say it's a perfect solution because the listener sticks around until it gets an event, and it's still somewhat dependent on garbage collection. We've been trying to replace it with explicit removal where possible, usually on addNotify/removeNotify on GUI components.
I'm using a multiplayer Game Client that's called AppWarp (http://appwarp.shephertz.com), where you can add event listeners to be called back when event's happen, let's assume we'll be talking about the Connection Listener, where you need to implement this interface:
public interface ConnectionRequestListener {
void onConnectDone(ConnectEvent var1);
void onDisconnectDone(ConnectEvent var1);
void onInitUDPDone(byte var1);
}
My goal here is to mainly create a Reactive version of this client to be used in my Apps Internally instead of using the Client itself directly (I'll also rely on interfaces later instead of just depending on the WarpClient itself as in the example, but that's not the important point, please read my question at the very end).
So what I did is as follows:
1) I introduced a new event, named it RxConnectionEvent (Which mainly groups Connection-Related events) as follows:
public class RxConnectionEvent {
// This is the original connection event from the source client
private final ConnectEvent connectEvent;
// this is to identify if it was Connection / Disconnection
private final int eventType;
public RxConnectionEvent(ConnectEvent connectEvent, int eventType) {
this.connectEvent = connectEvent;
this.eventType = eventType;
}
public ConnectEvent getConnectEvent() {
return connectEvent;
}
public int getEventType() {
return eventType;
}
}
2) Created some event types as follows:
public class RxEventType {
// Connection Events
public final static int CONNECTION_CONNECTED = 20;
public final static int CONNECTION_DISCONNECTED = 30;
}
3) Created the following observable which emits my new RxConnectionEvent
import com.shephertz.app42.gaming.multiplayer.client.WarpClient;
import com.shephertz.app42.gaming.multiplayer.client.events.ConnectEvent;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
public class ConnectionObservable extends BaseObservable<RxConnectionEvent> {
private ConnectionRequestListener connectionListener;
// This is going to be called from my ReactiveWarpClient (Factory) Later.
public static Observable<RxConnectionEvent> createConnectionListener(WarpClient warpClient) {
return Observable.create(new ConnectionObservable(warpClient));
}
private ConnectionObservable(WarpClient warpClient) {
super(warpClient);
}
#Override
public void call(final Subscriber<? super RxConnectionEvent> subscriber) {
subscriber.onStart();
connectionListener = new ConnectionRequestListener() {
#Override
public void onConnectDone(ConnectEvent connectEvent) {
super.onConnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_CONNECTED));
}
#Override
public void onDisconnectDone(ConnectEvent connectEvent) {
super.onDisconnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_DISCONNECTED));
}
// not interested in this method (for now)
#Override
public void onInitUDPDone(byte var1) { }
private void callback(RxConnectionEvent rxConnectionEvent)
{
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(rxConnectionEvent);
} else {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
};
warpClient.addConnectionRequestListener(connectionListener);
subscriber.add(Subscriptions.create(new Action0() {
#Override
public void call() {
onUnsubscribed(warpClient);
}
}));
}
#Override
protected void onUnsubscribed(WarpClient warpClient) {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
4) and finally my BaseObservable looks like the following:
public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {
protected WarpClient warpClient;
protected BaseObservable (WarpClient warpClient)
{
this.warpClient = warpClient;
}
#Override
public abstract void call(Subscriber<? super T> subscriber);
protected abstract void onUnsubscribed(WarpClient warpClient);
}
My question is mainly: is my implementation above correct or should I instead create separate observable for each event, but if so, this client has more than 40-50 events do I have to create separate observable for each event?
I also use the code above as follows (used it in a simple "non-final" integration test):
public void testConnectDisconnect() {
connectionSubscription = reactiveWarpClient.createOnConnectObservable(client)
.subscribe(new Action1<RxConnectionEvent>() {
#Override
public void call(RxConnectionEvent rxEvent) {
assertEquals(WarpResponseResultCode.SUCCESS, rxEvent.getConnectEvent().getResult());
if (rxEvent.getEventType() == RxEventType.CONNECTION_CONNECTED) {
connectionStatus = connectionStatus | 0b0001;
client.disconnect();
} else {
connectionStatus = connectionStatus | 0b0010;
connectionSubscription.unsubscribe();
haltExecution = true;
}
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
fail("Unexpected error: " + throwable.getMessage());
haltExecution = true;
}
});
client.connectWithUserName("test user");
waitForSomeTime();
assertEquals(0b0011, connectionStatus);
assertEquals(true, connectionSubscription.isUnsubscribed());
}
I suggest you avoid extending the BaseObservable directly since it's very error prone. Instead, try using the tools Rx itself gives you to create your observable.
The easiest solution is using a PublishSubject, which is both an Observable and a Subscriber. The listener simply needs to invoke the subject's onNext, and the subject will emit the event. Here's a simplified working example:
public class PublishSubjectWarpperDemo {
public interface ConnectionRequestListener {
void onConnectDone();
void onDisconnectDone();
void onInitUDPDone();
}
public static class RxConnectionEvent {
private int type;
public RxConnectionEvent(int type) {
this.type = type;
}
public int getType() {
return type;
}
public String toString() {
return "Event of Type " + type;
}
}
public static class SimpleCallbackWrapper {
private final PublishSubject<RxConnectionEvent> subject = PublishSubject.create();
public ConnectionRequestListener getListener() {
return new ConnectionRequestListener() {
#Override
public void onConnectDone() {
subject.onNext(new RxConnectionEvent(1));
}
#Override
public void onDisconnectDone() {
subject.onNext(new RxConnectionEvent(2));
}
#Override
public void onInitUDPDone() {
subject.onNext(new RxConnectionEvent(3));
}
};
}
public Observable<RxConnectionEvent> getObservable() {
return subject;
}
}
public static void main(String[] args) throws IOException {
SimpleCallbackWrapper myWrapper = new SimpleCallbackWrapper();
ConnectionRequestListener listner = myWrapper.getListener();// Get the listener and attach it to the game here.
myWrapper.getObservable().observeOn(Schedulers.newThread()).subscribe(event -> System.out.println(event));
listner.onConnectDone(); // Call the listener a few times, the observable should print the event
listner.onDisconnectDone();
listner.onInitUDPDone();
System.in.read(); // Wait for enter
}
}
A more complex solution would be to use one of the onSubscribe implementations to create an observable using Observable.create(). For example AsyncOnSubscibe. This solution has the benefit of handling backperssure properly, so your event subscriber doesn't become overwhelmed with events. But in your case, that sounds like an unlikely scenario, so the added complexity is probably not worth it.