My simple app works fine with .drl, but I wanted to check it with decision tables. Unfortunately, no tweaking and reading resolved the problem. I read that decision tables are not suitable to all kinds of tasks – are they in my case?
public static class UserInfo {
public enum Category {
var_1, var_2, var_3, var_4, var_5
}
public enum Degree {
high, medium, low;
}
}
My .drl looks like this:
item : UserInfo( variable_n == UserInfo.Category.var_1 ,
level_n == UserInfo.Degree.high) and
item2 : UserInfo( variable_n == UserInfo.Category.var_2 ,
level_n == UserInfo.Degree.high) etc...
The shortened decision table:
.
Related
I'm a beginner APEX developer (language based off of Java) and I was wondering if there is an efficient way to write conditional statements where two conditions change while the rest remains static.
For instance, in my code below, Countryy__c will change to say UK, US and Canada (besides France) and for each of these countries the Industry will change from Accounting to Medicine to Legal. Meanwhile, lead type and status will always remain as outbound and open respectively. Moreover each Country and Industry combination has a unique 'Owner ID'.
So in other words, there will be a total of 12 if/else statements with 12 different OwnerIds. Given that the code will be messy to maintain in the future if the number of countries and industries grow, is there a better way of coding this?
public static void changeOwnerToQueue(List<String> DeactivatedUserIds){
List<Lead> leadList = new List<Lead>();
List<lead> updatedQueue = new List<Lead>();
leadList = [SELECT Id, OwnerId, Countryy__c, Industry__c, Lead_Type__c, Status from lead
where OwnerId IN :DeactivatedUserIds];
for(Lead l : leadList){
if(l.Countryy__c == 'France' && l.Industry__c == 'Accounting' && l.Lead_Type__c == 'Outbound' && l.Status == 'Open'){
l.OwnerId = '00G5J000000pX41';
updatedQueue.add(l);
}
}
The most maintainable pattern for this kind of mapping in Apex is to use Custom Metadata. You'd create some Custom Metadata Type (MyOwnerMap__mdt), with fields for Country__c, Industry__c, and Owner__c. You'd create Custom Metadata records to represent all of your mappings. Then, in your code, you'd pull that data to create a Map, using a custom class as a key to represent the unique mapping of Country + Industry -> Owner:
class OwnerMapKey {
public String industry;
public String country;
public OwnerMapKey(String ind, String ctry) {
this.industry = ind;
this.country = ctry;
}
public Boolean equals(Object other) {
if (other instanceof OwnerMapKey) {
OwnerMapKey o = (OwnerMapKey)other;
return this.industry == o.industry && this.country == o.country;
}
return false;
}
public Integer hashCode() {
return (this.industry + this.country).hashCode();
}
}
List<MyOwnerMap__mdt> ownerMapValues = MyOwnerMap__mdt.getAll().values();
Map<OwnerMapKey, Id> ownerMap = new Map<OwnerMapKey, Id>();
for (MyOwnerMap__mdt eachOwnerMap: ownerMapValues) {
ownerMap.put(new OwnerMapKey(eachOwnerMap.Industry__c, eachOwnerMap.Country__c), eachOwnerMap.Owner__c);
}
Then, you can easily access the desired Owner value for any combination of Industry and Country. Note that you'll probably want to have a fallback if that entry is missing from your Custom Metadata.
someRecord.OwnerId = ownerMap.get(new OwnerMapKey(SOME_INDUSTRY, SOME_COUNTRY)) || defaultOwner;
(Disclaimer: above code written directly in Stack Overflow and untested).
The reason this pattern is valuable is that your solution then becomes admin-maintainable: you can change the mapping with no code changes and no deployment, just by altering the Custom Metadata records.
I'm creating a springboot banking API and in order to create a transaction a bunch of "rules" have to be checked.
e.g:
Current logged in user can't withdraw money from another user's savings account
Amount can't be higher/lower than certain number
etc.
This causes my createTransaction method to contain a lot of if statements (12!). This is what my code looks like in pseudo:
public ResponseEntity<String> createTransaction(Transaction body) {
if (check rule 1) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("...");
}
if (check rule 2) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("...");
}
// etc...
// Transaction complies to set rules
return ResponseEntity.status(HttpStatus.CREATED).body("Transaction successful!");
}
I can post my actual code if necessary but I think this paints the picture without having anyone to read 100 lines of code.
Because I have around 12 if statements checking these rules, my function is quite lengthy and difficult to read/maintain.
Googling for a solution didn't bring up results I was looking for. I've tried implementing exceptions but this didn't remove the amount of if statements. Maybe a switch could improve a bit, but I'm wondering if there's a clean OOP solution.
My question is: How can I clean this code up (OOP style)?
Thanks in advance.
You should create a TransactionRule interface that allows you to implement specific transaction rules, and then use a stream to get the final result:
public interface TransactionRule {
public boolean isAllowed(Transaction someTransaction);
}
Example implementation 1:
public class SufficientBudgetTransactionRule implements TransactionRule {
public boolean isAllowed(Transaction someTransaction) {
// Custom logic e.g.
return someTransaction.wallet.value >= someTransaction.transaction.value;
}
}
Example implementation 2:
public class NotInFutureTransactionRule implements TransactionRule {
public boolean isAllowed(Transaction someTransaction) {
// Custom logic e.g.
return someTransaction.transaction.datetime.isBefore(OffsetDateTime.now());
}
}
Then, you can store all the TransactionRules in a List and check whether they all validate like so:
private final List<TransactionRule> transactionRules; // Fill these of course
public boolean allTransactionRulesMatch(Transaction someTransaction) {
return transactionRules.stream()
.map(transactionRule -> transactionRule.isAllowed(someTransaction))
.allMatch(result => result);
}
I've got a query which returns data from several tables. In the application, these tables are classes one within another, for example a Client has several Orders, each Order has several OrderDetails, each OrderDetail has several Products, and so on... But I can't figure out a proper way to build the entire object in the app since the query returns one row for (let's just say) each product, so I have one client repeated over and over for every product it has bought.
So far I've tried this terribly inefficient code, and it works, problem is, it takes too much time for the app to process all of this information when it retrieves several clients.
boolean orderFound = false;
for (Order order1 : orders) {
if (order1 .getId() == order.getId()) {
orderFound = true;
if (od.getId() != 0) {
boolean odFound = false;
for (OrderDetail orderdetail : order1.getOrderDetail()) {
if (orderDetail.getId() == od.getId()) {
if (prod.getId() != 0) {
odFound = true;
boolean prodFound= false;
for (Product product: orderDetail.getProducts()) {
if (product.getId() == product.getId()) {
prodFound= true;
}
}
if (!prodFound) {
orderDetail.getProducts().add(dia);
}
}
if (!odFound) {
order1.getOrderDetail().add(od);
}
}
}
}
if (!orderFound) {
if (order.getId() != 0) {
orders.add(order);
This works, but there's gotta be a better way and I haven't found it. I've been told this can be solved using HashSets but I still don't know how to use them. Any help will be appreciated.
If you are open to using third party libraries, I think this is what you are looking for:
How to use hibernate to query for an object with a nested object that has a nested collection of objects
I am hoping to filter an ArrayList of custom model objects down to those matching user-selected values.
The user can filter the different fields of the model object in any manner...
If they select multiple values for the same field (e.g. choosing breakfast and dinner for the "category" field) objects matching any of the selections should be returned. If they simultaneously filter using the "protein" field and choose "chicken" only chicken breakfast and dinner meals should be returned.
I am currently using Guava and Collections2.filter(...), but can't seem to combine the AND/OR logic properly.
Any guidance would be appreciated! :)
Edit: Adding code snippet as an indication that I'm not looking for "moral support"
Collection<FieldAcceptanceLogItem> objectFilter = allLogItems;
for (final Filter filter : mFilters) {
objectFilter = Collections2.filter(objectFilter, new Predicate<FieldAcceptanceLogItem>() {
#Override
public boolean apply(#javax.annotation.Nullable FieldAcceptanceLogItem input) {
if (filter.getCategory().equalsIgnoreCase(getString(R.string.sublocation))) {
return input.getSublocation().equalsIgnoreCase(filter.getTitle());
}
else if (filter.getCategory().equalsIgnoreCase(getString(R.string.technology))) {
return input.getTechnology().equalsIgnoreCase(filter.getTitle());
}
else { //(filter.getCategory().equalsIgnoreCase(getString(R.string.component)))
return input.getComponent().equalsIgnoreCase(filter.getTitle());
}
}
});
}
So it looks like you want the intersection of sublocation, technology, and component. I moved a couple of things around that should highlight what you're trying to tackle:
objectFilter = Collections2.filter(objectFilter, new Predicate<FieldAcceptanceLogItem>() {
#Override
public boolean apply(#javax.annotation.Nullable FieldAcceptanceLogItem input) {
return SublocationFilters.from(mFilters).contains(input.getLocation())
&& TechnologyFilters.from(mFilters).contains(input.getTechnology())
&& ComponentFilters.from(mFilters).contains(input.getComponent());
});
SublocationFilters.from(...) will give you all of the sublocation filters
TechnologyFilters.from(...) will give you all of the tech filters
ComponentFilters.from(...) will give you all of the component filters
contains(...) is just a convinient method for doing "filter_1 OR filter_2 OR... filter_n"
If you do want to follow that pattern though, I'd recommend doing something more like this as it is less to write tests for:
new CategoryFilter(mFilters, getString(R.string.component))
.contains(input.getComponent());
My java project required that I create an array of objects(items), populate the array of items, and then create a main method that asks a user to enter the item code which spits back the corresponding item.
It took me a while to figure out, but I ended up "cheating" by using a public variable to avoid passing/referencing the object between classes.
Please help me properly pass the object back.
This is the class with most of my methods including insert and the find method.
public class Catalog {
private Item[] itemlist;
private int size;
private int nextInsert;
public Item queriedItem;
public Catalog (int max) {
itemlist = new Item[max];
size = 0;
}
public void insert (Item item) {
itemlist[nextInsert] = item;
++nextInsert;
++size;
}
public Item find (int key) {
queriedItem = null;
for (int posn = 0; posn < size; ++posn) {
if (itemlist[posn].getKey() == key) queriedItem = itemlist[posn];
}{
return queriedItem;
}
}
}
This is my main class:
import java.util.*;
public class Program {
public static void main (String[] args) {
Scanner kbd = new Scanner (System.in);
Catalog store;
int key = 1;
store = new Catalog (8);
store.insert(new Item(10, "food", 2.00));
store.insert(new Item(20, "drink", 1.00));
while (key != 0) {
System.out.printf("Item number (0 to quit) ?%n");
key = kbd.nextInt();
if (key == 0) {
System.out.printf("Exiting program now!");
System.exit(0);
}
store.find(key);
if (store.queriedItem != null) {
store.queriedItem.print();
}
else System.out.printf("No Item found for %d%n", key);
}
}
}
Thanks I appreciate the help!!!!!!
store.find(key); returns an Item you should use it and delete the public field from Catalog
public Item find (int key) {
Item queriedItem = null;
//....
}
Item searched = store.find(key);
if (searched != null)
searched.print();
else
System.out.printf("No Item found for %d%n", key);
Remove your use of queriedItem entirely and just return the item from find: Replace
store.find(key);
if (store.queriedItem != null){store.queriedItem.print();}else System.out.printf("No Item found for %d%n", key);
With
Item foundItem = store.find(key);
if (foundItem != null) {
foundItem.print();
} else System.out.printf("No Item found for %d%n", key);
Well, here are some suggesetions (choose complexity at your own discretion, but all of them is highly recommended):
Research Properties, for example here. Or XML. You could populate the array with values from a configuration file for greater flexibility.
Use constanst for literals in your code (where they are necessary).
Create an ApplicationFactory the initializes the whole application for you. Things like this need to be separated from your domain logic.
Create a UserInputProvider interface so you can easily change the way the input of the user is read without affecting anything else. Implement it with a ConsoleInputProvider class for example.
In general, try using interfaces for everything that's not a pure domain object (here, the only one you have is probably Item).
Try to keep your methods as short as possible. Instead of doing many things in a method, have it invoke other methods (grouping related logic) named appropriately to tell what it is doing.
If you're not allowed to cheat and use List or a Map, devise your own implementation of one, separating data structure and handling from the logic represented by Catalog (i.e. Catalog in turn will delegate to, for example, Map.get or equivalent method of your data structure implementation)
Your main should basically just have ApplicationFactory (or an IoC framework) to build and initialize your application, invoke the UserInputProvider (it should not know the exact implementation it is using) to get user input, validate and convert the data as required, invoke Catalog to find the appropriate Item and then (similarly to the input interface) send the result (the exact data it got, not some string or alike) to some implementation of a SearchResultView interface that decides how to display this result (in this case it will be a console-based implementation, that prints a string representing the Item it got).
Generally, the higher the level of decoupling you can achieve, the better your program will be.
The Single Responsibility Principle states: " every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class". This is also true for methods: they should have one and only one well defined task without any side effects.