How to refactor deeply nested functions? - if-statement

My code currently looks like this:
If (case = 1)
{
If (option = 1)
{
If (otherOption = 1)
;do something
else if (otherOption = 2)
;do something
else if (otherOption = 3)
;do something
}
else
{
If (otherOption = 1)
;do something
else if (otherOption = 2)
;do something
else if (otherOption = 3)
;do something
}
}
else if (case = 2)
{
If (option = 1)
{
If (otherOption = 1)
;do something
else if (otherOption = 2)
;do something
else if (otherOption = 3)
;do something
}
else
{
If (otherOption = 1)
;do something
else if (otherOption = 2)
;do something
else if (otherOption = 3)
;do something
}
}
else if (case = 3)
{
If (option = 1)
{
If (otherOption = 1)
;do something
else if (otherOption = 2)
;do something
else if (otherOption = 3)
;do something
}
else
{
If (otherOption = 1)
;do something
else if (otherOption = 2)
;do something
else if (otherOption = 3)
;do something
}
}
Obviously terrible and difficult to maintain. I want to add yet another super If statement on top of this, which splits this tree 6 times. Each ;do something does one line of code.
Any help on how to refactor this monstrosity? I've written a lot of code that looks like this and I dread working with it every time. I need a new way to approach these problems. Extending the functionality of this code requires a lot of work.

Even if you didn't specify the context of your application, it seems a scenario that could take advantage from the application of Strategy Pattern.
The code you posted can be settled to act as the Context object with the responsibility of control the higher level condition of your outer if-else statement.
Within every block of if-else statement, a particular behaviour can be loaded using a a ConcreteStrategy object (that usually implements a Strategy interface).
This pattern can be repeated for inner if-else blocks.
Example
Consider a game in which a Character moves around a 2D-map. Depending of its life indicator (e.g 0-200), it can moves of 2,5,8 tiles if he is,respectively,in a tired, ok or a super state.
The Character object acts like the "Context of the Strategy Pattern and he has the responsability of which MoveStrategy is correct for the situation.
Putting of life the correct MoveStrategy object and calling by forwarding the method move() throght the move() method of Character.
A hint for a Java implementation of the example:
public class Character{
private int life=100;
private int x=0
private int y=0;
private MoveStrategy strategy=new DefaultStrategy();
public int getLife(){
return life;
}
public void setLife(int value){
this.life=value;
}
public void move(){
if(life<30)
strategy=new TiredStrategy();
else if(life > 100)
strategy=new SuperStrategy();
else
strategy=new DefaultStrategy();
strategy.move();
}
}
public interface MoveStrategy{
public abstract void move();
}
public DefaultStrategy implements MoveStrategy{
public void move(){
System.out.println("Move character of 5 tiles");
}
}
public TiredStrategy implements MoveStrategy{
public void move(){
System.out.println("Move character of 2 tiles");
}
}
public SuperStrategy implements MoveStrategy{
public void move(){
System.out.println("Move character of 8 tiles");
}
}

Related

Problem with state change using useState in if else statement

I got some issue with useState and "if else" statement. I wanted to change displayed text with a click.
When I checking if counter icrement is working, it works, but when I add setText in "if else" statement there is a problem and just doesnt work properly. Icnrement strats to work strange when clicking and change a text is just imposible. Even in console increment looks wrong. Can someone help what I am doing wrong?
let counter = 0;
const [txt, setTxt] = useState("Text1");
const handleClick = (e) => {
if (
e.target.classList.contains("fa-angle-right") || e.target.classList.contains("fa-angle-left")
) {e.target.classList.contains("fa-angle-right") ? counter++ : counter--;
if (counter === 1) {
console.log(counter);
setTxt("Text2");
} else if (counter === 2) {
console.log(counter);
setTxt("Txt3")
} else if (counter > 2) {
counter = 0;
console.log(counter);
setTxt("Text1");
} else if (counter < 0) {
counter = 2;
console.log(counter);
setTxt("Text3");
} else if (counter === 0) {
console.log(counter);
setTxt("Txt1");
}
}
};
Every time setTxt('...') is executed, the component is re-rendered and the function executes again, so counter gets the value of 0.
If you want to preserve the value of your counter between renders, put it as a new state ( const [counter, setCounter] = useState(0) )
OK, #AdriánFernándezMartínez I did that way and its close. Just after first clik, in a first "if" (if (counter === 1)) console shows 0 and i have to click twice to chage it and change Txt (but is should be 1 after setCounter(counter + 1)). Next, in a third "if" (else if (counter > 2)) console shows 3 and again I need to click twice to change Txt (after 1st click its 0 and after 2nd it become 1). Still need help.
const [counter, setCounter] = useState(0);
const [txt, setTxt] = useState("Text1");
const handleClick = (e) => {
if (
e.target.classList.contains("fa-angle-right") ||
e.target.classList.contains("fa-angle-left")
) {
e.target.classList.contains("fa-angle-right")
? setCounter(counter + 1)
: setCounter(counter + 1);
console.log(counter);
if (counter === 1) {
console.log(counter);
setTxt("Text2");
} else if (counter === 2) {
console.log(counter);
setTxt("Text3");
} else if (counter > 2) {
setCounter(0);
console.log(counter);
setTxt("Text1");
} else if (counter < 0) {
setCounter(2);
console.log(counter);
setTxt("Text3");
} else if (counter === 0) {
console.log(counter);
setTxt("Text1");
}
}
};

Trouble detecting item used

I am trying to check if the item the player used is the custom item I added but for some reason it is not detecting the item. Here is the code.
#EventHandler
public void damage(EntityDamageByEntityEvent event){
if(event.getEntity() instanceof Player && event.getDamager() instanceof Player){
if(((Player) event.getDamager()).getInventory().getItemInMainHand() == CustomItems.potator()){
System.out.println("potato");
}
else{
//When i looked # console this logged the same exact thing
System.out.println("Damager Main Item = " + ((Player) event.getDamager()).getInventory().getItemInMainHand());
System.out.println("Potator Item = " + CustomItems.potator());
}
}
}
Custom Item Class:
public static ItemStack potator(){
ArrayList<String> lore = new ArrayList<String>();
lore.add(ChatColor.GOLD + "Turns a random slot in the hotbar to a potato.");
lore.add(ChatColor.GRAY + "1/100% chance from dropping from a potato.");
ItemStack item = new ItemStack(Material.STONE_HOE);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(ChatColor.GOLD + "The Potator");
meta.setLore(lore);
item.setItemMeta(meta);
return item;
}
if(((Player) event.getDamager()).getInventory().getItemInMainHand() == CustomItems.potator())
In this line, by using ==, you're checking if the left and right-hand references are the same. You want to do content comparison, e.g. using .equals(). There's a good explanation of the differences on GeeksForGeeks.
Spigot provides a stack size independent method isSimilar() which would be better than .equals().
However, this would likely make your code execute for any stone hoe so you'll need to do your own checks. I would do something like this:
public boolean isPotator(ItemStack i){
if(i == null || !i.hasItemMeta())
return false;
ItemMeta meta = i.getItemMeta();
if(!meta.hasDisplayName() || !meta.hasLore())
return false;
return meta.getDisplayName().equals(ChatColor.GOLD + "The Potator");
}
And then perform your check like so:
#EventHandler
public void damage(EntityDamageByEntityEvent event)
{
if(!(event.getEntity() instanceof Player && event.getDamager() instanceof Player))
return;
Player damager = (Player) event.getDamager();
if(!isPotator(damager.getInventory().getItemInMainHand()))
return;
System.out.println("potato");
}
Since you have a CustomItem class, you can better this code by making a final string for the item name, which you can then use in both the ItemStack creation and the isPotator check.

Why wont this IF statement work in Unity?

Okay I have a problem. I am using an IF statement. It seems to not run like it should. It works fine without the || condition, but with the || it seems to just pull the text under and not run the ELSE...
var fateText : UI.Text;
var inputText : UI.Text;
function fateBall () {
if(inputText.text == "illuminati"||"Illuminati"){
fateText.text = "We run the entire world. Join us!";
}else{
var myRandomString : String = RandomWordString(1);
fateText.text = myRandomString;
}
}
If i remove the ||"Illuminati" it works great... but like this it assigns fateText.text to "We run the entire world." and not the myRandomString
EDIT REPORT: Okay, the .ToLower() worked great now I am running into a problem where when I add multiple IFs it just bypasses the IFs and just runs the ELSE... any ideas?
function fateBall () {
if(inputText.text.ToLower() == "illuminati"){
fateText.text = "We run the entire world. Join us!";}
if(inputText.text.ToLower() == "satan"){
fateText.text = "Lucifer is the Light Bringer. He leads us against God!";}
if(inputText.text.ToLower() == "devil"){
fateText.text = "Lucifer is the Light Bringer. He leads us against God!";}
if(inputText.text.ToLower() == "lucifer"){
fateText.text = "Lucifer is the Light Bringer. He leads us against God!";}
else{
var myRandomString : String = RandomWordString(1);
fateText.text = myRandomString;
}
}
The condition must be :
if(inputText.text == "illuminati" || inputText.text == "Illuminati")
Otherwise, you can set to lower all the text so as to be case-independant :
if(inputText.text.ToLower() == "illuminati")
An even better way to compare strings is to use the Equals function (C# only though)
if( String.Equals( inputText.text, "illuminati", System.StringComparison.InvariantCultureIgnoreCase)
EDIT further to your EDIT:
string lowerText = inputText.text.ToLower() ;
if(lowerText == "illuminati")
{
fateText.text = "We run the entire world. Join us!";
}
else if(lowerText == "satan")
{
fateText.text = "Lucifer is the Light Bringer. He leads us against God!";
}
else if(lowerText == "devil")
{
fateText.text = "Lucifer is the Light Bringer. He leads us against God!";
}
else if(lowerText == "lucifer")
{
fateText.text = "Lucifer is the Light Bringer. He leads us against God!";
}
else
{
var myRandomString : String = RandomWordString(1);
fateText.text = myRandomString;
}
Try changing the condition from:
inputText.text == "illuminati"||"Illuminati"
To this:
inputText.text == "illuminati"|| inputText.text =="Illuminati"
I don't think you can chain conditions like that.
In addition you may want to just use a lowercase function to simplify your condition. So I believe you can do the following instead.
if(inputText.text.ToLower()=="illuminati")
If you want to check multiple condidtions in one if statement do it like this:
if (var1 == condition1 || var2 == condition2){}
this will check if either one return true, but you can also check if multiple statements are true by using:
if (var1 == condition1 && var2 == condition2){}

Multiple string comparisions

I'm trying to implement a very basic clone of redis in C++. So when I get the queries, I need to parse those. Right now I am doing this:
void Query::buildQuery(){
std::string query_type = lower(args[0]);
if(query_type == "get"){ //do something }
else if(query_type == "set"){ //do something }
else if(query_type == "getbit"){ //do something }
else if(query_type == "setbit"){ //do something }
else if(query_type == "zadd"){ //do something }
else if(query_type == "zcard"){ //do something }
else if(query_type == "zcount"){ //do something }
else if(query_type == "zrange"){ //do something }
else if(query_type == "save"){ //do something }
else { throw(QueryException("Invalid query type")); }
}
Is there any other, shorter way to do this? I don't want to include any other library than the STL.
If those do_somethings can be extracted into separate methods, then you could create a pre-initialized hash map (unordered_map) from string to pointer to member function and do something like
(this->*queryHandlers[query_type])();
You'll have to choose between lots of functions and one large function, though.
If you're running on an Intel/AMD processor and feeling 'brave' you might like to take a look at these implementations of strcmp, strlen, etc that use SSE instructions. That'd be quicker.
As for the general structure, you could turn "set" & "do something" into an class which has a test method and a do-something method. Have an array of those, and iterate across it calling the test method passing query_type. The test method for the object would automatically call the do-something method if it matches the string.
Without if...else if, you can do this by switch statement. Like:
void Query::buildQuery(){
std::string query_type = lower(args[0]);
switch(str2int(query_type) ){
case str2int("set"):// do something
break;
case str2int("getbit"):// do something
break;
................
..........
default:
throw(QueryException("Invalid query type"));
}
}
According to Serhiy where str2int is like:
constexpr unsigned int str2int(const char* str, int h = 0)
{
return !str[h] ? 5381 : (str2int(str, h+1)*33) ^ str[h];
}

Drupal adding a custom header per node

I have created the templeate html-landing.tpl.php and try to include it in a template with the following in my template.phpenter code here
function myfuntion_preprocess_html(&$variables, $hook) {
$node = menu_get_object();
if ($node->nid == 60) {
$variables['theme_hook_suggestions'][] = 'html-landing';
}
}
The code is called but the template used is the standard html.tpl.php.
Any ideas?
Have you tried using underscore instead of dash?
I'd go for something like this:
function myfunction_preprocess_html(&$variables, $hook) {
$node = menu_get_object();
if ($node && $node->nid == 60) {
$variables['theme_hook_suggestions'][] = 'html_landing';
}
}
More details at http://drupal.org/node/190815#comment-4167060