Jak pozbyć się powtórzeń? DRY

0

PYTANIE
Klasa PatternOption1 i PatternOption2 są prawie takie same. Jak to zmienić by było mniej powtórzeń?
Jedyne co mi przychodzi do głowy to zrobić dziedziczenie, ale podobno dziedziczenie jest złe.

Opis klas:
Test - test jednostkowy, cel agorytmu. Algorytm wyszukuje w tekście liczby większe od 1000 zapisane w dziwnych formatach np. 7k zwróci 7000, 7.5 zwróci 7500.
Mother - tworzy obiekt Engine zasilając go różnymi MyPattern, którego zachowanie jest określane przez obiekty implementujące IPatternOption.
Engine - silnik, przelatuje przez wszystkie MyPattern i robi calculate()

KOD

import junit.framework.TestCase;

public class Test extends TestCase {

	@org.junit.Test
	public void testcalculate1() {
		// Having:
		String text = "Zarabiam 7k";

		// When:
		Mother m = new Mother();
		Integer result = m.calculate(text);

		// Then:
		assertEquals(7000, result.intValue());
	}

	@org.junit.Test
	public void testcalculate2() {
		// Having:
		String text = "Zarabiam 7.5k";

		// When:
		Integer result = new Mother().calculate(text);

		// Then:
		assertEquals(7500, result.intValue());
	}

}
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Mother {

	Engine engine;

	public Mother() {
		Set<IPattern> set = new HashSet<>();
		set.add(new MyPattern("\\s\\d+k", new PatternOption1()));
		set.add(new MyPattern("\\s\\d+[,|.]\\d+k", new PatternOption2()));
		engine = new Engine(set);
	}

	public Integer calculate(String text) {
		List<Integer> result = engine.calculate(text);
		return result.stream().filter(p -> p != null).findFirst().orElse(null);
	}
}

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

public class Engine {
	
	Set<IPattern> patternRules;
	
	public Engine(Set<IPattern> set){
		this.patternRules = set;
	}
	
	public List<Integer> calculate(String text){
		List<Integer> result = new ArrayList<>();
		for (IPattern p : patternRules) {
			result.add(p.getPattern(text));
		}
		return result;
	}

}
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyPattern implements IPattern{

	String regex;
	IPatternOption predicate;
	
	public MyPattern(String regex, IPatternOption predicate){
		this.regex = regex;
		this.predicate = predicate;
	}
	
	@Override
	public Integer getPattern(String text) {
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(text);

		while (m.find()) {
			String tmp = m.group();
			tmp = tmp.replace(" ", "");
			predicate.compile(tmp);
			
			if (predicate.test()) {
				return predicate.getValue(); // return first match
			}
		}
		return null; // if there wasn't matched pattern
	}

}
public interface IPatternOption {

	public void compile(String t);
	
	public boolean test();
	
	public Integer getValue();
}
public class PatternOption1 implements IPatternOption{
	private Integer number;
	final private int MIN_NUMBER = 1000;

	@Override
	public void compile(String text) {
		
		String tmp = text.replace("k", "");
		int x = Integer.parseInt(tmp) * 1000;
		this.number = x;
	}

	@Override
	public boolean test() {
		return number >= MIN_NUMBER;
	}

	@Override
	public Integer getValue() {
		return number;
	}
}
public class PatternOption2 implements IPatternOption{
	private Integer number;
	final private int MIN_NUMBER = 1000;

	@Override
	public void compile(String text) {
		String tmp = text.replace("k", "");
		String[] partNumber = tmp.split("[,|.]");
		int x = Integer.parseInt(partNumber[0]) * 1000 + Integer.parseInt(partNumber[1]) * 100;
		this.number = x;
	}

	@Override
	public boolean test() {
		return number >= MIN_NUMBER;
	}

	@Override
	public Integer getValue() {
		return number;
	}
}
0

Nazwij te klasy porządnie i zrób delegację, niech PatternOption2 wywołuje metody test() i getValue() obiektu PatternOption1. (przekazanego w konstruktorze)

2
Julian_ napisał(a):

PYTANIE
Klasa PatternOption1 i PatternOption2 są prawie takie same. Jak to zmienić by było mniej powtórzeń?
Jedyne co mi przychodzi do głowy to zrobić dziedziczenie, ale podobno dziedziczenie jest złe.

Nie wierz we wszystko co czytasz w internecie. Zrób dziedziczenie tutaj.

2

Wersja przerobiona troszeczkę (i bez dzieczenia... ale to wcale nie znaczy, że dobrze).
nie znam do końca twoich intencji , więc przerabiałem mało.
Imo cały ten kod (bez testu) to kandydat na 3-5 linijkowca :-)

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

public class Engine {

    Set<MyPattern> patternRules;

    public Engine(Set<MyPattern> set){
        this.patternRules = set;
    }

    public List<Integer> calculate(String text){
        List<Integer> result = new ArrayList<>();
        for (MyPattern p : patternRules) {
            p.getPattern(text).ifPresent( result::add);
        }
        return result;
    }

}
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

public class Mother {

    Engine engine;

    public Mother() {
        Set<MyPattern> set = new HashSet<>();
        set.add(new MyPattern("\\s\\d+k", PatternOption1::compile));
        set.add(new MyPattern("\\s\\d+[,|.]\\d+k", PatternOption2::compile));
        engine = new Engine(set);
    }

    public Optional<Integer> calculate(String text) {
        List<Integer> result = engine.calculate(text);
        return result.stream().findFirst();
    }
}
import java.util.Optional;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyPattern {
    private final  static int MIN_NUMBER = 1000;
    final String regex;
    final Function<String, Integer> compile;


    public MyPattern(String regex, Function<String, Integer> compile){
        this.regex = regex;
        this.compile = compile;
    }

    public Optional<Integer> getPattern(String text) {
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(text);

        while (m.find()) {
            String tmp = m.group();
            tmp = tmp.replace(" ", "");
            final int value = compile.apply(tmp);

            if (value >MIN_NUMBER) {
                return Optional.of(value);
            }
        }
        return Optional.empty();
    }

}
public class PatternOption1 {

    public static int compile(String text) {
        String tmp = text.replace("k", "");
        return  Integer.parseInt(tmp) * 1000;
    }
}
public class PatternOption2 {
    public static int  compile(String text) {
        String tmp = text.replace("k", "");
        String[] partNumber = tmp.split("[,|.]");
        return Integer.parseInt(partNumber[0]) * 1000 + Integer.parseInt(partNumber[1]) * 100;
    }
}
import junit.framework.TestCase;

import java.util.Optional;

public class Test extends TestCase {

    @org.junit.Test
    public void testcalculate1() {
        // Having:
        String text = "Zarabiam 7k";

        // When:
        Mother m = new Mother();
        Optional<Integer> result = m.calculate(text);

        // Then:
        assertEquals(Optional.of(7000), result);
    }

    @org.junit.Test
    public void testcalculate2() {
        // Having:
        String text = "Zarabiam 7.5k";

        // When:
        Optional<Integer>result = new Mother().calculate(text);

        // Then:
        assertEquals(Optional.of(7500), result);
    }

}

1 użytkowników online, w tym zalogowanych: 0, gości: 1