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.
Related
I am trying to implement Strategy pattern approach for payment processing in my Spring webflux based application.
My application supports multiple payment method like, Card Payment, Cash Payment, ...
Also, we have to support Square & Stripe for Card payment.
Model class,
// Model interface
public interface PaymentModel {
}
// Base model with attributes needed for all payment types
public class BaseModel implements PaymentModel {
private Float amount;
private Integer userId;
}
public class SquareCardModel extends BaseModel {
private String merchantId;
private String device;
private String orderId;
}
public class StripeCardModel extends BaseModel {
private String merchantId;
private String orderId;
}
public class CashModel extends BaseModel {
private String name;
private String orderId;
}
Service Class,
#Service
public interface PaymentService<T extends PaymentModel> {
Mono<ServerResponse> pay(T model);
String method();
}
#Service
public class CashPaymentService implements PaymentService<CashModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(CashModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
#Service
public class SquarePaymentService implements PaymentService<SquareCardModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(SquareCardModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
#Service
public class StripePaymentService implements PaymentService<StripeCardModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(SquareCardModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
Factory Class,
#Service
public class PaymentFactory<T> {
private final List<PaymentService<? extends PaymentModel>> paymentServices;
#Autowired
public PaymentFactory(List<PaymentService<? extends PaymentModel>> paymentServices) {
this.paymentServices = paymentServices;
}
public PaymentService<? extends PaymentModel> retrievePaymentService(final String paymentMethod) {
Optional<PaymentService<? extends PaymentModel>> paymentService = paymentServices.stream()
.filter(service -> service.method().equals(paymentMethod)).findFirst();
if (paymentService.isEmpty()) {
throw new IllegalArgumentException("Unsupported Payment method ");
}
return paymentService.get();
}
}
User choose the payment method and the call comes to the backend,
#Transactional
public Mono<ServerResponse> payBilling(ServerRequest request) {
return request.bodyToMono(PaymentDto.class).flatMap(paymentReq -> {
if (paymentReq.getPaymentType().equals("CC")) { // For Card
return processCardPayment(usr, paymentReq);
} else {
return badRequest().bodyValue("Not supported yet !");
}
});
}
private Mono<? extends ServerResponse> processCardPayment(
PaymentDto paymentReq) {
PaymentService<PaymentModel> paymentService = (PaymentService<PaymentModel>) paymentFactory
.retrievePaymentService(paymentReq.getPaymentType());
PaymentModel paymentModel = buildPaymentModel((String) paymentReq.getPaymentType(), paymentReq,
jsonMap);
return paymentService.pay(paymentModel);
}
private PaymentModel buildPaymentModel(final String paymentMethod, final PaymentDto paymentReq,
if (paymentMethod.equals("squarePayment")) {
SquareCardModel model = new SquareCardModel();
model.setAmount(paymentReq.getTotal());
model.setMerchantId(paymentReq.getMerchantid());
model.setOrderId(orderId);
return model;
}
return null;
}
Questions:
Not sure if I have implemented generics properly with the strategy pattern.
Also, I dont like type casting here. (PaymentService). is there any better approach?
Why do I still need to use if for creating different model.
if (paymentMethod.equals("squarePayment")) {
PaymentService<PaymentModel> paymentService = (PaymentService<PaymentModel>) paymentFactory
.retrievePaymentService(paymentReq.getPaymentType());
PaymentModel paymentModel = buildPaymentModel((String) paymentReq.getPaymentType(), paymentReq,
jsonMap);
return paymentService.pay(paymentModel);
Here's a simplified version of your code which I think maintains what you need to do, from a type perspective:
import java.util.Optional;
public class App {
public interface PaymentModel { }
public static class CashModel implements PaymentModel { }
public interface PaymentService<T extends PaymentModel> {
void pay(T model);
void pay2(PaymentModel model);
}
public static class PaymentFactory {
public PaymentService<PaymentModel> retrievePaymentService(final String paymentMethod) {
Optional<PaymentService<PaymentModel>> paymentService = null;
return paymentService.get();
}
public PaymentService<? extends PaymentModel> retrievePaymentService2(final String paymentMethod) {
Optional<PaymentService<PaymentModel>> paymentService = null;
return paymentService.get();
}
}
public static void main(String... args) throws NoSuchFieldException, IllegalAccessException {
PaymentFactory paymentFactory = null;
PaymentService<PaymentModel> paymentService = paymentFactory
.retrievePaymentService("foo");
paymentService.pay(new CashModel());
PaymentService<? extends PaymentModel> paymentService2 = paymentFactory
.retrievePaymentService2("foo");
paymentService2.pay(new CashModel()); // error
paymentService2.pay2(new CashModel()); // ok
}
}
Look at the difference between retrievePaymentService and retrievePaymentService2.
retrievePaymentService returns PaymentService<PaymentModel> which says that it is a payment service which works on any PaymentModel implementation.
retrievePaymentService2 returns PaymentService<? extends PaymentModel> which says that it is a payment service which works on some specific, unknown PaymentModel implementation.
As you have already made sure that your PaymentModel type matches the PaymentService you are getting from the factory, the first form is what you want.
A better design might try to not have two parallel class hierarchies which need to be matched up carefully at runtime.
Also, processCardPayment seems as though it should handle all PaymentModels?
I have two classes:
public class UnoLoginPageUi {
public final Input username = new Input("id=username");
public final Input password = new Input("id=password");
public final Button loginButton = new Button("name=login");
}
and
public class DuoLoginPageUi {
public final Input username = new Input("id=usernameField");
public final Input password = new Input("id=passwordField");
public final Button loginButton = new Button("id=submitButton");
}
and in one common class I want to make something like that:
public void loginUsingUsernameAndPassword(String username, String password, String pageType) {
getUi(pageType).username.waitForToBeDisplayed();
getUi(pageType).username.setValue(username);
getUi(pageType).password.setValue(password);
getUi(pageType).loginButton.click();
}
where getUi() is a method that gas argument pageType (which is UNO or DUO).
private Class getUi(String pageType) {
if (pageType.equals("UNO")) {
return new DuoLoginPageUi();
}
else if (pageType.equals("DUO")) {
return new UnoLoginPageUi;
}
return null;
}
However it doesn't work as this method need to in type of this two pages with selectors - how to deal with that ?
You can create a interface called LoginPageUi. And let your UnoLoginPageUi and DuoLoginPageUi implement that interface.
Then your getUi method will be private LoginPageUi getUi(String pageType).
Off topic: I would recommend to implement an enum instead of String pageType.
Create a common abstraction for the two classes
public abstract class LoginPageUi {
public final Input username = new Input("id=username");
public final Input password = new Input("id=password");
public final Button loginButton = new Button("name=login");
}
and have UnoLoginPageUi and DuoLoginPageUi extend that
public class UnoLoginPageUi extends LoginPageUi {
public static String getPageType() { return "UNO"; }
}
public class DuoLoginPageUi extends LoginPageUi {
public static String getPageType() { return "DUO"; }
}
The method would return the common abstraction
private LoginPageUi getUi(String pageType) {
if (pageType.equals(DuoLoginPageUi.getPageType())) {
return new DuoLoginPageUi();
}
else if (pageType.equals(UnoLoginPageUi.getPageType())) {
return new UnoLoginPageUi;
}
return null;
}
I also hope you realize that every time you call getUi(pageType) it is returning a new instance. by the time you call getUi(pageType).loginButton.click(); the instance returned has no values set.
Refactor:
public void loginUsingUsernameAndPassword(String username, String password, String pageType) {
LoginPageUi ui = getUi(pageType);
if (ui != null) {
ui.username.waitForToBeDisplayed();
ui.username.setValue(username);
ui.password.setValue(password);
ui.loginButton.click();
}
}
create Parent class or interface for both called UI:
public abstract class Ui{
}
public interface Ui{
}
and extend it:
public class UnoLoginPageUi extends Ui{
public final Input username = new Input("id=username");
public final Input password = new Input("id=password");
public final Button loginButton = new Button("name=login");
}
public class DuoLoginPageUi extends Ui {
public final Input username = new Input("id=usernameField");
public final Input password = new Input("id=passwordField");
public final Button loginButton = new Button("id=submitButton");
}
or
public class UnoLoginPageUi implements Ui{
public final Input username = new Input("id=username");
public final Input password = new Input("id=password");
public final Button loginButton = new Button("name=login");
}
public class DuoLoginPageUi implements Ui {
public final Input username = new Input("id=usernameField");
public final Input password = new Input("id=passwordField");
public final Button loginButton = new Button("id=submitButton");
}
then return parent reference as:
private Ui getUi(String pageType) {
if (pageType.equals("UNO")) {
return new DuoLoginPageUi();
}
else if (pageType.equals("DUO")) {
return new UnoLoginPageUi;
}
return null;
}
I have a java controller class, when ever save action is invoked in any item say Product or coverage or Limit , it calls the controller save method and a parameter is passed. The if logic in the controller checks the argument and call the save method of the appropriate object. The if logic is increasing day by day. Can any one suggest better design pattern?
Code:
public class Product {
public void save(PolicyData p){
//logic here
}
}
public class Coverage {
public void save(PolicyData p){
//logic here
}
}
public class Limit {
public void save(PolicyData p){
//logic here
}
}
public class Controller {
private Product pr=new Product();
private Limit lim=new Limit();
private Coverage cov=new Coverage();
public void save(PolicyData p,String item){
if(item.equals("Product")){
pr.save(p);
}if(item.equals("Coverage")){
cov.save(p);
}if(item.equals("Limit")){
lim.save(p);
}
}
}
Create a Saveable interface:
public interface Saveable {
public void save(String p);
}
your classes implement the interface, and then create a Map:
private Map<String, Saveable> saveMap = new HashMap<>();
Fill it with Savable objects and then call the save method based on the String.
public enum SaveableType {
PRODUCT, COVERAGE, LIMIT
}
public class Controller {
private Product pr = new Product();
private Limit lim = new Limit();
private Coverage cov = new Coverage();
private Map<SaveableType, Saveable> saveableMap = new HashMap<>();
public Controller() {
saveableMap.put(SaveableType.PRODUCT, pr);
saveableMap.put(SaveableType.LIMIT, lim);
saveableMap.put(SaveableType.COVERAGE, cov);
}
// better to use enum for the 2nd parameter not a String
public void save(PolicyData p, String item) {
SaveableType saveables = SaveableType.valueOf(item.toUpperCase());
saveableMap.get(saveables).save(p);
}
}
Create an interface that has save method
Implement the method in your object
In your controller create a map to hold objects against the key that you are comparing now in your if
code:
public interface Myinterface {
public void save(PolicyData p);
}
public class Product implements Myinterface{
public void save(PolicyData p){
//logic here
}
public class Controller {
private static HashMap<String,Myinterface> map=new HashMap<String,Myinterface>();
public Controller(){
map.put("Product", new Product());
map.put("Limit", new Limit());
map.put("Coverage", new Coverage());
}
public void save(PolicyData p,String item){
Myinterface m=map.get(item);
m.save(p);
}
}
}
Not really a solution to reduce the if-else jungle. But this might look more "beautiful".
http://www.w3schools.com/js/js_switch.asp
So in your case:
switch(item) {
case("Product"): pr.save(item); break;
// and so on...
}
I'm stuck on this assignment. I'm given an abstract Observer class with only 1 constructor in it, a constructor with parameters/arguments. (refer below)
public static void main(String[] args) {
PairOfNumbers numbers1 = new PairOfNumbers();
PairOfNumbers numbers2 = new PairOfNumbers();
SumObserver sum = new SumObserver(numbers1);
ProductObserver prod = new ProductObserver(numbers2);
MultiSubjectObserver m = new MultiSubjectObserver();
m.addSubject(numbers1);
m.addSubject(numbers2);
numbers1.setNumbers(20, 10);
numbers2.setNumbers(-10, 15);
}
class Subject {
private List<Observer> observers=new ArrayList<Observer>();
public void attachObserver(Observer observer) {
this.observers.add(observer);
}
public void detachObserver(Observer observer) {
this.observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer: this.observers)
observer.update(this);
}
}
class PairOfNumbers extends Subject {
private double number1, number2;
public double getNumber1() { return this.number1; }
public double getNumber2() { return this.number2; }
public void setNumbers(double d1, double d2) {
this.number1=d1; this.number2=d2;
this.notifyObservers(); // don't forget to do this!
}
}
abstract class Observer {
public Observer(Subject subject) {
subject.attachObserver(this);
}
abstract public void update(Subject subject);
}
class SumObserver extends Observer {
public SumObserver(PairOfNumbers pair) {
super(pair);
}
public void update(Subject subject) {
PairOfNumbers numbers=(PairOfNumbers)subject;
System.out.println("New sum is: "+(numbers.getNumber1()+numbers.getNumber2()));
}
}
class ProductObserver extends Observer {
public ProductObserver(PairOfNumbers pair) {
super(pair);
}
public void update(Subject subject) {
PairOfNumbers numbers=(PairOfNumbers)subject;
System.out.println("New product is: "+(numbers.getNumber1()*numbers.getNumber2()));
}
}
Okay, now I'm suppose to create another class which inherits from the above class.
class MultiSubjectObserver extends Observer{
public MultiSubjectObserver(PairOfNumbers pair){
super(pair);
}
public void addSubject(PairOfNumbers pair){
pair.attachObserver(this);
}
public void update(Subject subject){
PairOfNumbers numbers=(PairOfNumbers)subject;
System.out.println("MultiSubjectObserver activated with numbers: " + (numbers.getNumber1())+", "+(numbers.getNumber2()));
}
}
Is there a way to create a constructor inside the MSO Class which requires no parameter/argument? For example
public MultiSubjectObserver(){
//enter code here
}
Please guide me on this one. Had been thinking for days. Thanks in advance! :D
The instruction is to: Modify the source code to handle any number of Subject objects per Observer.
Expected output:
New sum is: 30.0
MultiSubjectObserver activated with numbers: 20.0, 10.0
New product is: -150.0
MultiSubjectObserver activated with numbers: -10.0, 15.0
Yes you can do this, create a no-arg child class, but you still must call the arg-needing super constructor within the child constructor.
This:
class Child extends Super {
public Child() {
super(args_are_needed);
}
}
The tricky part would be -- what to pass into the super constructor in this default case? In your case this could be:
public MultiSubjectObserver(){
super(null);
}
Caveat: and this will lead to a NullPointerException when the super's constructor is called, due to the line, subject.attachObserver(this);, so no, you can't do this.
A better solution: make sure that MultiSubjectObserver does not extend from Observer!
Perhaps something like:
class MultiSubjectObserver {
private List<Observer> observerList = new ArrayList<Observer>();
public void addSubject(PairOfNumbers numbers1) {
observerList.add(new InnerObserver(numbers1));
}
private class InnerObserver extends Observer {
public InnerObserver(Subject subject) {
super(subject);
}
#Override
public void update(Subject subject) {
System.out.println("From multi-observer: " + subject);
}
}
}
But for this to work, you'd have to give PairOfNumbers a decent toString method, perhaps,
#Override
public String toString() {
return String.format("[%.4f, %.4f]", number1, number2);
}
Edit
Based on the output:
class MultiSubjectObserver {
private static final String FORMAT_STRING = "MultiSubjectObserver activated with numbers: %.1f, %.1f%n";
private List<Observer> observerList = new ArrayList<Observer>();
public void addSubject(PairOfNumbers numbers1) {
observerList.add(new InnerObserver(numbers1));
}
private class InnerObserver extends Observer {
public InnerObserver(Subject subject) {
super(subject);
}
#Override
public void update(Subject subject) {
System.out.printf(FORMAT_STRING, ((PairOfNumbers)subject).getNumber1(), ((PairOfNumbers)subject).getNumber1());
}
}
}
Although that casting is a bit skanky. I like the toString() version much better.
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();
}