1
\$\begingroup\$

I know basic Java, but I struggle sometimes with object orientation design.

There is a vendor api I use, and I wanted to wrap it to be reusable as a lib in other projects. All the services from the vendor are different classes and have no hierarchy and so on, but I have no option to change it. So I want to use composition and ensure I don't repeat myself.

I thought initially to create a service that would receive the parameters that are common to all services, and this service would implement the api.

I tried refactoring this code here and there, and I'm pretty sure this design I'm trying has some great problems as I noticed when trying to create unit tests :)

How could I achieve a better design? Code as of now:


1) Vendor code (I can't change this)

VendorServiceCake.java

package example;
public class VendorServiceCake {
    public VendorApiCake getCakeApi(int i) {
        //vendor code
        return new VendorApiCake();
    }
}

VendorApiCake.java

package example;
public class VendorApiCake {
    public void authenticate(String user, String password, int parameterNeeded) {/*vendor code*/}
    public void cookDeliciousCake(CakeIngredients ingredients) {/*vendor code*/}
}

VendorServiceSellPie.java

package example;
public class VendorServiceSellPie {
    public VendorApiSellPie getPieApi(int i) {
        //vendor code
        return new VendorApiSellPie();
    }
}

VendorApiSellPie.java

package example;
public class VendorApiSellPie {
    public void authenticate(String user, String password, int parameterNeeded) {/*vendor code*/}
    public void sellDeliciousPie(Object customer) {/*vendor code*/}
}

2) This is how I currently invoke the vendor api

ExampleCurrent.java

package example;
public class ExampleCurrent {
    void exampleCake() {
        VendorServiceCake vendorServiceCake = new VendorServiceCake();
        VendorApiCake cakeApi = vendorServiceCake.getCakeApi(1234);
        cakeApi.authenticate("user", "password", 1234);
        CakeIngredients ingredients = null;
        cakeApi.cookDeliciousCake(ingredients);
    }
    void exampleSellPie() {
        VendorServiceSellPie vendorServiceSellPie = new VendorServiceSellPie();
        VendorApiSellPie apiSellPie = vendorServiceSellPie.getPieApi(1234); //same parameters as above
        apiSellPie.authenticate("user", "password", 1234); //same parameters as above
        Object customer= null;
        apiSellPie.sellDeliciousPie(customer);
    }
}

3) This is what I want it too look like when users use my .jar

UsageOfMyNewApi.java

package example;

import java.util.ArrayList;
import java.util.List;

public class UsageOfMyNewApi {
    void usage() {
        BakeryServiceCake service = new BakeryServiceCake("user", "password", 1234);
        CakeIngredients ingredients = null;
        service.cookDeliciousCake(ingredients);
    }
    void usage2() {
        BakeryServiceSellPie service = new BakeryServiceSellPie("user", "password", 1234);
        List<Customer> customers = new ArrayList<>();
        customers.add(new Customer("john"));
        service.sellDeliciousPie(customers);
    }
}

4) Code needs refactoring for better design

BakeryService.java

package example;
import java.util.List;
public abstract class BakeryService { //is this class useless?
    public BakeryService(String user, String password, int parameterNeeded) {}
    private void checkParameters() {/*do some checkings of the parameters*/}
}

BakeryServiceCake.java

package example;
public class BakeryServiceCake extends BakeryService implements KitchenCakeApi {
    private KitchenCakeApi api;
    public BakeryServiceCake(String user, String password, int parameterNeeded) {
        super(user, password, parameterNeeded);
        this.api = new KitchenCakeApiImpl(user,password, parameterNeeded);
    }
    @Override
    public void authenticate() {
        api.authenticate();
    }
    public void cookDeliciousCake(CakeIngredients ingredients) {
        api.cookDeliciousCake(ingredients);
    }
}

BakeryServiceSellPie.java

package example;
import java.util.List;
public class BakeryServiceSellPie extends BakeryService /* will implement SellingCakeApi */ {
    public BakeryServiceSellPie(String user, String password, int i) {
        super(user, password, i);
    }
    public void sellDeliciousPie(List<Customer> customers) {/*to be implemented yet as the BakeryServiceCake, but not the main point as of now*/}
}

KitchenCakeApi.java

package example;
public interface KitchenCakeApi {
    void authenticate();
    void cookDeliciousCake(CakeIngredients cakeIngredients);
}

KitchenCakeApiImpl.java

package example;
public class KitchenCakeApiImpl implements KitchenCakeApi {
    private final String user;
    private final String password;
    private final int parameterNeeded;
    private VendorServiceCake vendorServiceCake;
    private VendorApiCake cakeApi;

    public KitchenCakeApiImpl(String user, String password, int parameterNeeded) {
        this.user = user;
        this.password = password;
        this.parameterNeeded = parameterNeeded;
        vendorServiceCake = new VendorServiceCake();
        cakeApi = vendorServiceCake.getCakeApi(parameterNeeded);
    }

    @Override
    public void authenticate() {
        cakeApi.authenticate(user, password, parameterNeeded);
    }

    @Override
    public void cookDeliciousCake(CakeIngredients cakeIngredients) {
        cakeApi.cookDeliciousCake(cakeIngredients);
    }
}

Beans

CakeIngredients.java

package example;
public class CakeIngredients {}

Customer.java

package example;
public class Customer {
    public Customer(String john) {}
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.