My question is about what should be the most OOP solution and the right design pattern for my situation. We have a user entity and multiple account entities belong to the user. Account entities can have multiple states and we can execute multiple operations on accounts. The outcome of these operations is based on the account entity's state.
I have the following code which is based mostly on switch (sometimes it looks like a few "if"). I would like to change it but cannot find the right design pattern.
enum Status {
ACTIVE, INACTIVE, DELETED;
}
#Entity
class Account {
private long id;
private long userid;
private Status status;
//...
}
class AccountService{
Account delete(long id) {
//...
if (accountInfo.getSatus() == DELETED) {
throw new IllegalOperationException();
}
if (accountInfo.getStatus() == ACTIVE || accountInfo.getStatus()) {
accountInfo.setStatus(DELETED);
accountInfoRepository.save(accountInfo);
}
}
Account create (Account account) {
// various operations based on state
}
}
I really want to refactor these codes, I fear that as soon as our service grows it will contain more "magic" and will be hard to maintain. And if we would like to introduce a new state it will be nearly impossible.
My junior mind thought that I should have state objects which would implement all the operations, in pseudo-code style:
class AccountService {
private StateFactory stateFactory;
private AccountRepository accountRepository;
Account delete(long id) {
final Optional<Account> account = accountRepository.findById(id);
Account deletedAccount = account.map(stateFactory::getByState)
.map(accountState -> accountState.delete(account))
.orElseThrow(() -> new IllegalOperationException());
return accountRepository.save(deletedAccount);
}
Account create (Account account) {
// various operation based on state
}
}
and:
class ActiveState extends AccountState {
#Override
public Account delete(Account account) {
//implementation
}
#Override
public Account activate(AccountInfo) {
// implementation
}
}
and:
interface AccountState {
Account activate(AccountInfo);
Account delete(AccountInfo);
}
I know there must be a better implementation for this problem. Which other design patterns are suitable for this setup?
UPDATE
I have found a few interesting articles to read in the topic:
How to implement a FSM - Finite State Machine in Java
When you have more complex state handling
If I understood question correctly, then it is necessary to apply some action by its state.
If it is true, then we can use Factory pattern to get desired object which can execute some action. Mapping between state and action can be putted into HashTable.
So let's see an example of code. I will write via C#, but this code can be easily translated to Java because languages have many syntax similarities.
So we will have enum of statuses:
public enum Status
{
Active,
Deleted,
Foo
}
and states of AccountState
public abstract class AccountState
{
public abstract void ExecSomeLogic();
}
public class ActiveState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}
public class DeletedState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}
public class FooState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}
Then we need mapper class of Status to their AccountState:
public class StatusToAccountState
{
public Dictionary<Status, AccountState> AccountStateByStatus { get; set; } =
new Dictionary<Status, AccountState>() // HashMap in Java
{
{ Status.Active, new ActiveState() },
{ Status.Deleted, new DeletedState() },
{ Status.Foo, new FooState() },
};
}
And then in your service you can use it like this:
void Delete(long id, Status status)
{
StatusToAccountState statusToAccountState = new StatusToAccountState();
AccountState accountState = statusToAccountState.AccountStateByStatus[status];
accountState.ExecSomeLogic();
}
If there are many logic to figure out what Status of object is, then you can create some class which will have just one responisibility of figuring out what state of object is:
public class StatusManager
{
public Status Get()
{
return Status.Active; // or something another based on logic
}
}
After doing this, your classes will correspond to the single responsibility principle of SOLID. Read more about single responsibility principle of SOLID here
Too many switch-/if-Statements indicate the code smell "Tool Abusers" (see M. Fowler "Refactoring"). Use the polymorphism mechanics to solve this.
https://refactoring.guru/smells/switch-statements
Related
I have controller method that get data from request and based on subject variable from request decide to call a function. (for project need I cannot use seperate controller method for each subject variable)
For now I used switch but I think it breaks Open Closed Principle (because every time new type of subject added I have to add new case to switch) and not good design, How can I refactor this code?
Subject subject = ... //(type of enum)
JSONObject data = request.getData("data");
switch(subject) {
case SEND_VERIFY:
send_foo1(data.getString("foo1_1"), data.getString("foo1_2"));
break;
case do_foo2:
foo2(data.getInt("foo2_b"), data.getInt("foo2_cc"));
break;
case do_foo3:
do_foo3_for(data.getString("foo3"));
break;
// some more cases
}
While I am not sure about which OO principle this snippet violates, there is indeed a more roust way to achieve the logic: tie the processing for each enum value to the enum class.
You will need to generalize the processing into an interface:
public interface SubjectProcessor
{
void process(JSONObject data);
}
and create concrete implementations for each enum value:
public class SendVerifySubjectProcessor implements SubjectProcessor
{
#Override
public void process(JSONObject data) {
String foo1 = data.getString("foo1_1");
String foo2 = data.getString("foo1_2");
...
}
}
once you have that class hierarchy tree, you can associate each enum value to a concrete processor
public enum Subject
{
SEND_VERIFY(new SendVerifySubjectProcessor()),
do_foo2(new Foo2SubjectProcessor()),
...
private SubjectProcessor processor
Subject(SubjectProcessor processor) {
this.processor = processor;
}
public void process(JSONObject data) {
this.processor.process(data);
}
}
This eliminates the need for the switch statement in the controller:
Subject subject = ... //(type of enum)
JSONObject data = request.getData("data");
subject.process(data);
EDIT:
Following the good comment, You can utilize the java.util.function.Consumer functional interface instead of the custom SubjectProcessor one. You can decide whether to write concrete classes or use the lambda expr construct.
public class SendVerifySubjectProcessor implements Consumer<JSONObject>
{
#Override
public void accept(JSONObject data) {
String foo1 = data.getString("foo1_1");
String foo2 = data.getString("foo1_2");
...
}
}
OR
public enum Subject
{
SEND_VERIFY(data -> {
String foo1 = data.getString("foo1_1");
String foo2 = data.getString("foo1_2");
...
}),
...
private Consumer<Subject> processor
Subject(Consumer<Subject> processor) {
this.processor = processor;
}
public void process(JSONObject data) {
this.processor.accept(data);
}
}
// SubjectsMapping.java
Map<Subject, Consumer<JSONObject>> tasks = new HashMap<>();
tasks.put(SEND_VERIFY,
data -> send_foo1(data.getString("foo1_1"), data.getString("foo1_2")));
tasks.put(do_foo2,
data -> foo2(data.getInt("foo2_b"), data.getInt("foo2_cc")));
tasks.put(do_foo3, data -> do_foo3_for(data.getString("foo3")));
// In your controller class where currently `switch` code written
if (tasks.containsKey(subject)) {
tasks.get(subject).accept(data);
} else {
throw new IllegalArgumentException("No suitable task");
}
You can maintain Map<Subject, Consumer<JSONObject>> tasks configuration in separate class rather than mixing with if (tasks.containsKey(subject)) code. When you need another feature you can configure one entry in this map.
Answers of others seems to be great, as an addition I would suggest using EnumMap for storing enums as keys as it might be more efficient than the standard Map. I think it's also worth mentioning that the Strategy Pattern is used here to achieve calling specific actions for each key from Map without the need of building long switch statements.
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:
/* This is how I call the service from the vendor today */
class VendorConsumer {
void exampleCake() {
VendorServiceCake vendorServiceCake = new VendorServiceCake();
VendorApiCake cakeApi = a.getCakeApi(1234);
cakeApi.authenticate("user", "password");
cakeApi.cookDeliciousCake(CakeIngredients ingredients);
}
void exampleSellPie() {
VendorServiceSellPie vendorServiceSellPie = new VendorServiceSellPie();
VendorApiSellPie apiSellPie = a.getPieApi(1234); //same parameters as above
apiSellPie.authenticate("user", "password"); //same parameters as above
apiSellPie.sellDeliciousPie(List<Customer> customer);
}
}
// ---------------------------------------------
/* Below is what I'm trying to do */
class UsageTest {
// This is how users of my .jar would call it
void usage() {
BakeryService service = new BakeryServiceCake("user", "password", 1234);
List<Cake> cakeList = service.cookDeliciousCake(CakeIngredients ingrediets);
}
void usage2() {
BakeryService service = new BakeryServiceSellPie("user", "password", 1234);
List<Payments> payments = service.sellDeliciousPie(List<Customer> customer);
}
}
class BakeryService { //is this class useless?
public BakeryService(String user, String pass, int parameterNeeded) {
}
private void checkParameters() {
//do some checkings of the parameters
}
}
class BakeryServiceCake extends BakeryService implements KitchenCakeApi {
KitchenCakeApi api;
public BakeryServiceCake(String user, String pass, int parameterNeeded) {
super(user, pass, parameterNeeded);
this.api = new KitchenCakeApiImpl(user, pass, parameterNeeded)
}
#Override
public void authenticate() {
api.authenticate();
}
#Override
public void cookDeliciousCake(CakeIngredients ingredients) {
api.cookDeliciousCake(ingredients);
}
}
interface KitchenCakeApi {
void authenticate();
void cookDeliciousCake(CakeIngredients ingredients);
}
class KitchenCakeApiImpl implements KitchenCakeApi {
private VendorServiceCake vendorServiceCake;
private VendorApiCake cakeApi;
public KitchenCakeApiImpl(String user, String pass, int parameterNeeded) {
vendorServiceCake = new VendorServiceCake();
cakeApi = a.getCakeApi(parameterNeeded); // that 1234
}
#Override
public void authenticate() {
cakeApi.authenticate("user", "password");
}
#Override
public void cookDeliciousCake(CakeIngredients ingredients) {
cakeApi.cookDeliciousCake(CakeIngredients ingredients);
}
}
Thanks!
The API's generally have some hierarchy/structure to it but you will need a keen eye to observe it, let's just say Java File handling is based on decorator pattern that too almost exact text book implementation.
Hard to answer without seeing the vendor API.
Probable Approach -
Use Adapter pattern help to encapsulates you from third party API.
Adapter has a cost to it which is lots of code to write but maintenance is easier.
If Adapters explode use it with proxy pattern to make a life bit easier.
Facade can help you in case of complex operations but this could be just an add-on in your case.
Two cents - http://www.oodesign.com/ go through design patterns just as an overview and see the problem it solves if it rings a bell go deeper else move on.
Happy designing.
I have learning the book Cracking the Coding Interview, and having some questions about the Chapter 8: Object-Oriented Design. Take the question 8.7 as an example:
8.7 Explain how you would design a chat server. In particular, provide details about the various backend components, classes, and methods. What would be the hardest problems to solve?
The solution can be found this github repo.
My general question is: how to assign different methods to different classes in order to complete a functionality? Is there some principles or common ideas of making these interactions? Take one specific functionality - User A adds User B - as an example:
The following is partial code of UserManager:
public class UserManager {
...
public void addUser(User fromUser, String toAccountName) {
User toUser = usersByAccountName.get(toAccountName);
AddRequest req = new AddRequest(fromUser, toUser, new Date());
toUser.receivedAddRequest(req);
fromUser.sentAddRequest(req);
}
public void approveAddRequest(AddRequest req) {
req.status = RequestStatus.Accepted;
User from = req.getFromUser();
User to = req.getToUser();
from.addContact(to);
to.addContact(from);
}
public void rejectAddRequest(AddRequest req) {
req.status = RequestStatus.Rejected;
User from = req.getFromUser();
User to = req.getToUser();
from.removeAddRequest(req);
to.removeAddRequest(req);
}
...
}
The following is partial code of User:
public class User {
...
public boolean addContact(User user) {
if (contacts.containsKey(user.getId())) {
return false;
} else {
contacts.put(user.getId(), user);
return true;
}
}
public void receivedAddRequest(AddRequest req) {
int senderId = req.getFromUser().getId();
if (!receivedAddRequests.containsKey(senderId)) {
receivedAddRequests.put(senderId, req);
}
}
public void sentAddRequest(AddRequest req) {
int receiverId = req.getFromUser().getId();
if (!sentAddRequests.containsKey(receiverId)) {
sentAddRequests.put(receiverId, req);
}
}
public void removeAddRequest(AddRequest req) {
if (req.getToUser() == this) {
receivedAddRequests.remove(req);
} else if (req.getFromUser() == this) {
sentAddRequests.remove(req);
}
}
public void requestAddUser(String accountName) {
UserManager.getInstance().addUser(this, accountName);
}
...
}
I am just wondering where approveAddRequest(AddRequest req) and rejectAddRequest(AddRequest req) are called. After AddRequest is sent or received, no further behaviors will be done for really process this request.
And also, I am wondering: should every interaction between class be like this (i.e., lots of methods from different classes are calling and called many times)?
What you're looking for is "Observer" Pattern.
It's best-practice introduced by GoF for event handling.
What you've presented here has nothing to do with chat. It's just utility for dealing with user interaction.
As for you last question: you're not seeing full code, so you can't know where it's called from. You should find full source code first. And you're right, with presented code no behaviour would be done, but for real chat there should be. This whole things is a mock.
The title might not be very clear but i could not figure out a better one. Here is the problem. I have a Scope interface which gives all the pages where a QueryEngine should query in.
interface Scope{
Set<Page> getPages();
}
interface QueryEngine{
void query(Scope scope){
queryIn(scope.getPages());
}
}
There is another type of scope which says query all the pages other than the ones it provides.
I was trying to model this behavior.
interface ExcludeScope extends Scope{
}
In which case i have to do something like below in QueryEngine
interface QueryEngine{
void query(Scope scope){
if(scope instanceof ExcludeScope){
queryInPagesOtherThan(scope.getPages());
}else{
queryIn(scope.getPages());
}
}
}
Or should it be something which is driven by a boolean
interface Scope{
Set<Page> getPages();
boolean shouldExclude();
}
I feel both the above approaches would lead to if, else conditions in the QueryEngine
which means that it is not closed for modifications.
How to design such a behaviour? What should be the approach one should follow while tackling any design problem? Should we start by checking whether SOLID principles were followed? Should we look to classify the problem under a design pattern thus arrive at a solution?
One possibility is to perform an inversion of control: The QueryEngine asks a Scope whether to process a page or not and the Scope answers independently true or false, similar to
interface Scope {
boolean process(Page page);
}
interface QueryEngine {
void query(Scope scope, Set<Page> pages) {
Set<Pages> pagesToProcess = new HashSet<Page>();
for (Page page : pages) {
if (scope.process(page)) {
pagesToProcess.add(page);
}
}
queryIn(pagesToProcess);
}
}
class IncludeScope implements Scope {
private static final Set<Page> INCLUDING_PAGES = ...
public boolean process(Page page) {
return INCLUDING_PAGES.contains(page);
}
}
class ExcludeScope implements Scope {
private static final Set<Page> EXCLUDING_PAGES = ...
public boolean process(Page page) {
return !EXCLUDING_PAGES.contains(page);
}
}
In my opinion the root of your problem is in this sentence:
There is another type of scope which says query all the pages other than the ones it provides".
Scope has nothing to do with querying, it should only represent a subset of all elements. You seem to want to perform a query in a different way, so I would suggest to go for a new method in the QueryEngine:
interface QueryEngine{
void query(Scope scope){
...
}
void queryComplement(Scope scope) {
...
}
}
I am going to develop a web crawler using java to capture hotel room prices from hotel websites.
In this case I want to capture room price with the room type and the meal type, so my algorithm should be intelligent to handle that.
For example:
Room type: Deluxe
Meal type: HalfBoad
price : $20.00
The main problem is room prices can be in different ways in different hotel sites. So my algorithm should be independent from hotel sites.
I am plan to use above room types and meal types as a fuzzy sets and compare the words in webpage with above fuzzy sets using a suitable membership function.
Anyone experienced with this? or have an idea for my problem?
There are two ways to approach this problem:
You can customize your crawler to understand the formats used by different Websites; or
You can come up with a general ("fuzzy") solution.
(1) will, by far, be the easiest. Ideally you want to create some tools that make this easier so you can create a filter for any new site in minimal time. IMHO your time will be best spent with this approach.
(2) has lots of problems. Firstly it will be unreliable. You will come across formats you don't understand or (worse) get wrong. Second, it will require a substantial amount of development to get something working. This is the sort of thing you use when you're dealing with thousands or millions of sites.
With hundreds of sites you will get better and more predictable results with (1).
As with all problems, design can let you deliver value adapt to situations you haven't considered much more quickly than the general solution.
Start by writing something that parses the data from one provider - the one with the simplest format to handle. Find a way to adapt that handler into your crawler. Be sure to encapsulate construction - you should always do this anyway...
public class RoomTypeExtractor
{
private RoomTypeExtractor() { }
public static RoomTypeExtractor GetInstance()
{
return new RoomTypeExtractor();
}
public string GetRoomType(string content)
{
// BEHAVIOR #1
}
}
The GetInstance() ,ethod lets you promote to a Strategy pattern for practically free.
Then add your second provider type. Say, for instance, that you have a slightly more complex data format which is a little more prevalent than the first format. Start by refactoring what was your concrete room type extractor class into an abstraction with a single variation behind it and have the GetInstance() method return an instance of the concrete type:
public abstract class RoomTypeExtractor
{
public static RoomTypeExtractor GetInstance()
{
return SimpleRoomTypeExtractor.GetInstance();
}
public abstract string GetRoomType(string content);
}
public final class SimpleRoomTypeExtractor extends RoomTypeExtractor
{
private SimpleRoomTypeExtractor() { }
public static SimpleRoomTypeExtractor GetInstance()
{
return new SimpleRoomTypeExtractor();
}
public string GetRoomType(string content)
{
// BEHAVIOR #1
}
}
Create another variation that implements the Null Object pattern...
public class NullRoomTypeExtractor extends RoomTypeExtractor
{
private NullRoomTypeExtractor() { }
public static NullRoomTypeExtractor GetInstance()
{
return new NullRoomTypeExtractor();
}
public string GetRoomType(string content)
{
// whatever "no content" behavior you want... I chose returning null
return null;
}
}
Add a base class that will make it easier to work with the Chain of Responsibility pattern that is in this problem:
public abstract class ChainLinkRoomTypeExtractor extends RoomTypeExtractor
{
private final RoomTypeExtractor next_;
protected ChainLinkRoomTypeExtractor(RoomTypeExtractor next)
{
next_ = next;
}
public final string GetRoomType(string content)
{
if (CanHandleContent(content))
{
return GetRoomTypeFromUnderstoodFormat(content);
}
else
{
return next_.GetRoomType(content);
}
}
protected abstract bool CanHandleContent(string content);
protected abstract string GetRoomTypeFromUnderstoodFormat(string content);
}
Now, refactor the original implementation to have a base class that joins it into a Chain of Responsibility...
public final class SimpleRoomTypeExtractor extends ChainLinkRoomTypeExtractor
{
private SimpleRoomTypeExtractor(RoomTypeExtractor next)
{
super(next);
}
public static SimpleRoomTypeExtractor GetInstance(RoomTypeExtractor next)
{
return new SimpleRoomTypeExtractor(next);
}
protected string CanHandleContent(string content)
{
// return whether or not content contains the right format
}
protected string GetRoomTypeFromUnderstoodFormat(string content)
{
// BEHAVIOR #1
}
}
Be sure to update RoomTypeExtractor.GetInstance():
public static RoomTypeExtractor GetInstance()
{
RoomTypeExtractor extractor = NullRoomTypeExtractor.GetInstance();
extractor = SimpleRoomTypeExtractor.GetInstance(extractor);
return extractor;
}
Once that's done, create a new link for the Chain of Responsibility...
public final class MoreComplexRoomTypeExtractor extends ChainLinkRoomTypeExtractor
{
private MoreComplexRoomTypeExtractor(RoomTypeExtractor next)
{
super(next);
}
public static MoreComplexRoomTypeExtractor GetInstance(RoomTypeExtractor next)
{
return new MoreComplexRoomTypeExtractor(next);
}
protected string CanHandleContent(string content)
{
// Check for presence of format #2
}
protected string GetRoomTypeFromUnderstoodFormat(string content)
{
// BEHAVIOR #2
}
}
Finally, add the new link to the chain, if this is a more common format, you might want to give it higher priority by putting it higher in the chain (the real forces that govern the order of the chain will become apparent when you do this):
public static RoomTypeExtractor GetInstance()
{
RoomTypeExtractor extractor = NullRoomTypeExtractor.GetInstance();
extractor = SimpleRoomTypeExtractor.GetInstance(extractor);
extractor = MoreComplexRoomTypeExtractor.GetInstance(extractor);
return extractor;
}
As time passes, you may want to add ways to dynamically add new links to the Chain of Responsibility, as pointed out by Cletus, but the fundamental principle here is Emergent Design. Start with high quality. Keep quality high. Drive with tests. Do those three things and you will be able to use the fuzzy logic engine between your ears to overcome almost any problem...
EDIT
Translated to Java. Hope I did that right; I'm a little rusty.