首页 > 解决方案 > 如何在没有实例变量和泛型的情况下实现方法

问题描述

我正在做一个项目,我需要用新的 ExpFoo 替换旧的 ExpFoo。

一个例子是给出一个 ExpFoo ((x * y) + (x * z)) 并且我们有新的 IntFoo, 2,它将替换 Varfoo, x。我们有一个 PlusFoo (a + b),它将替换 Varfoo, y。

所以结果将是: ((2 * (a + b) + (2 * z))

这是它在 Main 类上的外观:

import java.util.Arrays;

public class Main {

public static void main(String[] args) {

    ExpFoo e1 = new IntFoo(1);
    ExpFoo e2 = new IntFoo(2);
    ExpFoo e5 = new IntFoo(5);
    ExpFoo x = new VarFoo("x");
    ExpFoo plus = new PlusFoo(e1, e2);
    ExpFoo times = new TimesFoo(e5, x);
    ExpFoo bigTimes = new TimesFoo(plus, times);

    ExpFoo[] exps = { e1, e2, e5, x, plus, times, bigTimes };
    System.out.println(Arrays.toString(exps));

    Replacement r = new Replacement();
    r.put(new VarFoo("x"), new PlusFoo(e1, e5));
    System.out.println(r);

    for (ExpFoo exp : exps) {
        System.out.println(exp + " has " + exp.numberOfNodes() + " nodes and after applying " + r  + " the value " + exp.computeValue(r));
    }

    ExpFoo ex1 = new PlusFoo(new TimesFoo(new VarFoo("x"), new VarFoo("y")),new TimesFoo(new VarFoo("x"), new VarFoo("z")));
    Replacement repl = new Replacement();
    repl.put(new VarFoo("x"), new IntFoo(2));
    repl.put(new VarFoo("y"), new PlusFoo(new VarFoo("a"), new VarFoo("b")));
    ExpFoo ex2 = ex1.applyReplacement(repl);
    System.out.println("ex1: " + ex1);
    System.out.println("ex2: " + ex2);

}
}

我有两个问题:

  1. 我无法得到 times 和 bigTimes 的值。
  2. 我无法让 applyReplacement(repl) 工作。

对于第一个问题,我无法获得ExpFoo times = new TimesFoo(e5, x);ExpFoo bigTimes = new TimesFoo(plus, times);使用的值,exp.computeValue(r)因为我无法弄清楚如何计算 1 + 5 到 6。

我得到的只是一个异常,上面写着:UnsupportedOperationException:无法计算没有替换的 varfoo 的值!

对于时间,它应该返回为 (5 * x) 有 3 个节点,并且在应用 [x:=(1 + 5)] 后值为 30
对于 bigTimes,它应该返回为((1 + 2) * (5 * x) ) 有 7 个节点,在应用 [x:=(1 + 5)] 后值为 90

对于第二个问题,我遇到了问题 ExpFoo ex2 = ex1.applyReplacement(repl);

它返回一个异常TimesExpFoo cannot be cast to class com.company.VarFoo我无法让它工作。它应该返回((2 * (a + b) + (2 * z))

我不允许为除 Replacement 之外的所有类创建实例变量。

我也不能在所有类中都使用泛型。

这是它如何工作的说明,Replacement 类在所有类中都是分开的。

UML 图像在这里

对于课程,这是我迄今为止所做的。

Varfoo 类:

import java.util.Set;

/**
* A VarFoo is a symbolic ExpFoo that stands for a value that has not yet
* been fixed. A VarFoo has a name of the format
* letter (letter | digit)^*
* (where '(letter | digit)^*' stands for 'a string of length 0 or more that
* contains only letters and digits').
* Here the class methods Character.isLetter(char) and
* Character.isLetterOrDigit(char) determine whether a character is
* a letter/a letter or a digit, respectively.
* Instances of this class are immutable.
*/
public class VarFoo implements ExpFoo {

/**
 * Name of this VarFoo. Non-null, of the format
 * <p>
 * letter (letter | digit)*
 */
private String name;

/**
 * Constructs a new VarFoo with the specified name.
 *
 * @param name must not be null; must be a String of the format letter
 *             (letter | digit)^*
 */

public VarFoo(String name) {
    this.name = name;
}

@Override
public int numberOfNodes() {
    return 1;
}

@Override
public int computeValue() {
    throw new UnsupportedOperationException("Cannot compute the value of a varfoo without a replacement!");
}

@Override
public int computeValue(Replacement repl) {
    //TODO;
}

@Override
public ExpFoo applyReplacement(Replacement s) {
    //TODO
}

@Override
public boolean isVarFooFree() {
    // TODO
    return true;
}

@Override
public Set<VarFoo> getVarfoo() {
    return null;
}

@Override
public void collectVarfoo(Set<VarFoo> vars) {
    for (char c : name.toCharArray()) {
        if (Character.isAlphabetic(c)){
            vars.add(new VarFoo(name));
        }
    }
}

@Override
public String toString() {
    return name;
}

/**
 * The method returns true if o is an instance of class VarFoo
 * whose name is equal to the name of this VarFoo; otherwise it
 * returns false.
 *
 * @return whether this VarFoo and Object o are equal
 */
@Override
public boolean equals(Object o) {
    if (o == null) return false;
    if (!(o instanceof VarFoo))
        return false;
    if (o == this)
        return true;
    return name.equals(((VarFoo) o).name);
}

@Override
public int hashCode() {
    int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;


}
}

替换类:

import java.util.HashMap;
import java.util.Map;

/**
* A Replacement represents a mapping of finitely many VarFoo to
* ExpFoo. One can construct an empty Replacement, update a Replacement
* by adding/replacing/forgetting mappings of VarFoo to ExpFoo, and
* query Replacements for the value to which they map a varfoo, whether they
* have a mapping for a specific varfoo, and for a String representation.
*/
public class Replacement {

private Map<VarFoo, ExpFoo> replacementMap;

/**
 * Constructs an empty Replacement (i.e., a Replacement that does not
 * hold mappings for any varfoo(s).
 */
public Replacement() {
    replacementMap = new HashMap<>();
}

/* Mutators */

/**
 * Associates the specified ExpFoo with the specified Varfoo in this
 * Replacement. If the Replacement previously contained a mapping for the
 * Varfoo, the old ExpFoo is replaced.
 *
 * @param var the Varfoo with which exp is to be associated
 * @param exp the ExpFoo to which var is to be mapped
 * @return the ExpFoo to which var was mapped so far, or null if var did
 * not yet have a mapping in this Replacement
 * @throws NullPointerException if var or exp is null
 */
public ExpFoo put(VarFoo var, ExpFoo exp) {
    return replacementMap.put(var, exp);
}

/**
 * Forgets the mapping for the specified Varfoo. Does not modify this
 * Replacement if it does not have a mapping for the specified Varfoo.
 *
 * @param var the Varfoo for which we want to forget the mapping
 * @return whether a mapping for var was forgotten due to the method call
 * @throws NullPointerException may be thrown if var is null
 */
public boolean forget(VarFoo var) {
    if (var == null) {
        return true;
    }
    else {
        replacementMap.clear();
        return true;
    }
}

/* Accessors */

/**
 * Returns the value to which the specified Varfoo is mapped, or null if
 * this Replacement contains no mapping for the specified Varfoo.
 *
 * @param var the Varfoo for which we want the corresponding ExpFoo to
 *            which it is mapped
 * @return the ExpFoo to which this Replacement maps var, or var if
 * this Replacement does not have a mapping for var
 * @throws NullPointerException may be thrown if var is null
 */
public ExpFoo get(VarFoo var) {
    return replacementMap.get(var);
}

/**
 * Returns whether this Replacement has an explicit mapping of var to an
 * ExpFoo.
 *
 * @param var the Varfoo for which we want to know if this Replacement
 *            has a mapping
 * @return whether this Replacement has an explicit mapping of var to an
 * ExpFoo
 * @throws NullPointerException may be thrown if the parameter is null
 */
public boolean hasMappingFor(VarFoo var) {
    return replacementMap.containsValue(var);
}

@Override
public String toString() {
    String s = "";
    for (Map.Entry<VarFoo, ExpFoo> ReplacementKey : replacementMap.entrySet()) {
        s = "[" + ReplacementKey.getKey() + ":=" + ReplacementKey.getValue() + "]";
    }
    return s;
}
}

ExpFoo 类:

import java.util.LinkedHashSet;
import java.util.Set;

/**
* Basic interface for arithmetic ExpFoo. Implementations are expected to
* be immutable, i.e., after object creation, the object's state cannot change,
* and there are no mutator methods in any class that implements this interface.
*/
public interface ExpFoo {

/**
 * Computes the number of sub-ExpFoo of this ExpFoo (its "size").
 *
 * @return the number of nodes of this ExpFoo.
 */
int numberOfNodes();

/**
 * Computes the int value represented by this ExpFoo object. This
 * ExpFoo object must not contain Varfoos.
 *
 * @return the int value represented by this ExpFoo
 */
int computeValue();

/**
 * Computes the int value represented by this ExpFoo.
 *
 * @param repl
 *            to be used to assign values to this ExpFoo; must not be
 *            null
 * @return the int value represented by this ExpFoo
 * @throws UnsupportedOperationException
 *             if the ExpFoo with repl applied to it still has
 *             Varfoo
 * @throws NullPointerException
 *             if s is null
 */
default int computeValue(Replacement repl) {
    ExpFoo specialised = applyReplacement(repl);
    return specialised.computeValue();
}

/**
 * Returns whether this ExpFoo is VarFoo-free, i.e., none of its
 * direct or indirect sub-ExpFoo is a VarFoo object.
 *
 * @return whether this ExpFoo is VarFoo-free, i.e., none of its
 *         direct or indirect sub-ExpFoo is a VarFoo object.
 */
boolean isVarFooFree();

/**
 * Returns the Set of Varfoo of this ExpFoo. The returned Set may be
 * modified.
 *
 * @return the Set of Varfoo of this ExpFoo
 */
default Set<VarFoo> getVarfoo() {
    Set<VarFoo> result = new LinkedHashSet<>();
    collectVarfoo(result);
    return result;
}

/**
 * Adds all Varfoo in this ExpFoo to vars
 *
 * @param vars
 *            Varfoo will be added here; parameter must not be null
 * @throws NullPointerException
 *             if vars is null
 */
void collectVarfoo(Set<VarFoo> vars);

/**
 * Applies a Replacement to this ExpFoo and returns the result.
 *
 * @param r
 *            a Replacement to be applied to this ExpFoo; must not be
 *            null
 * @return a version of this ExpFoo where all Varfoo have been
 *         replaced by the values stored in s for the Varfoo
 * @throws NullPointerException
 *             if s is null
 */
ExpFoo applyReplacement(Replacement r);
}

BinaryFoo 类:

import java.util.Set;

/**
* Abstract class for ExpFoos with two direct subExpFoos. Provides an
* implementation for numberOfNodes() method. Instances of this class are immutable.
*/
public abstract class BinaryFoo implements ExpFoo {

/** the left subExpFoo; non-null */
private ExpFoo left;

/** the right subExpFoo; non-null */
private ExpFoo right;

/** String representation of the operator symbol; non-null */
private String operatorSymbol;

/**
 * Constructs a BinaryFoo with left and right as direct
 * subExpFoo and with operatorSymbol as the String representation of
 * the operator.
 *
 * @param left
 *            the left subExpFoo; non-null
 * @param right
 *            the right subExpFoo; non-null
 * @param operatorSymbol
 *            String representation of the operator symbol; non-null
 */
public BinaryFoo(ExpFoo left, ExpFoo right,
                 String operatorSymbol) {
    if (left == null) {
        throw new NullPointerException("Illegal null value for left!");
    }
    if (right == null) {
        throw new NullPointerException("Illegal null value for right!");
    }
    if (operatorSymbol == null) {
        throw new NullPointerException(
                "Illegal null value for operatorSymbol!");
    }
    this.left = left;
    this.right = right;
    this.operatorSymbol = operatorSymbol;
}

/**
 * Getter for the left subExpFoo.
 *
 * @return the left subExpFoo
 */
public ExpFoo getLeft() {
    return left;
}

/**
 * Getter for the right subExpFoo.
 *
 * @return the right subExpFoo
 */
public ExpFoo getRight() {
    return right;
}

/**
 * Getter for the operator symbol.
 *
 * @return the operator symbol
 */
public String getOperatorSymbol() {
    return operatorSymbol;
}

@Override
public int numberOfNodes() {
    return 1 + left.numberOfNodes() + right.numberOfNodes();
}

@Override
public void collectVariables(Set<VarFoo> vars) {
    vars.add((VarFoo)left);
    vars.add((VarFoo)right);
}

@Override
public boolean isVarFooFree() {
    // TODO
    return false;
}

@Override
public String toString() {
    return "(" + left + " " + operatorSymbol + " " + right + ")";
}

@Override
public boolean equals(Object o) {
    if (!(o instanceof BinaryFoo)) {
        return false;
    }
    BinaryFoo other = (BinaryFoo) o;
    // relies on instance variables being non-null
    return operatorSymbol.equals(other.operatorSymbol)
            && left.equals(other.left) && right.equals(other.right);
}

@Override
public int hashCode() {
    int result = (left == null) ? 0 : left.hashCode();
    result += (right == null) ? 0 : right.hashCode();
    return result;
}
}

TimesFoo 类:

/**
* Represents an ExpFoo of the form e1 * e2.
* Instances of this class are immutable.
*/
public class TimesFoo extends BinaryFoo {

/**
 * Constructs a TimesFoo with left and right as direct
 * subExpFoo.
 */
public TimesFoo(ExpFoo left, ExpFoo right) {
    super(left, right, "*");
}

@Override
public int computeValue() {
    return getLeft().computeValue() * getRight().computeValue();
}

@Override
public int computeValue(Replacement subst) {
    return computeValue();
}

@Override
public ExpFoo applyReplacement(Replacement r) {
    ExpFoo e = s.get((VarFoo)getVarFoo());
    return e;
}

@Override
public boolean equals(Object o) {
    if (!(o instanceof TimesFoo)) {
        return false;
    }
    return super.equals(o);
}

@Override
public int hashCode() {
    return super.hashCode();
}
}

PlusFoo 类:

/**
* Represents an ExpFoo of the form e1 + e2.
* Instances of this class are immutable.
*/
public class PlusFoo extends BinaryFoo {

/**
 * Constructs a PlusFoo with left and right as direct subExpFoos.
 *
 * @param left  the left subExpFoo; non-null
 * @param right the right subExpFoo; non-null
 */
public PlusFoo(ExpFoo left, ExpFoo right) {
    super(left, right, "+");
}

@Override
public int computeValue() {
    return getLeft().computeValue() + getRight().computeValue();
}

@Override
public ExpFoo applyReplacement(Replacement r) {
    ExpFoo e = s.get((VarFoo)getVarFoo());
    return e;
}

@Override
public int computeValue(Replacement repl) {
    return computeValue();
}

@Override
public boolean equals(Object o) {
    if (!(o instanceof PlusFoo)) {
        return false;
    }
    return super.equals(o);
}

@Override
public int hashCode() {
    return super.hashCode();
}
}

IntFoo 类:

import java.util.Objects;
import java.util.Set;

/**
* ExpFoo that represents an int value.
*/
public class IntFoo implements ExpFoo {

/**
 * Stores the encapsulated value.
 */
private int value;

/**
 * Constructs a new IntFoo encapsulating value.
 *
 * @param value to be encapsulated in this IntFoo
 */
public IntFoo(int value) {
    this.value = value;
}

/**
 * @return the int value this IntFoo stands for
 */
public int getValue() {
    return value;
}

@Override
public int numberOfNodes() {
    return 1;
}

@Override
public int computeValue(Replacement repl) {
    return computeValue();
}

@Override
public int computeValue() {
    return value;
}

@Override
public ExpFoo applyReplacement(Replacement r) {
    VarFoo var = new Variable(name); //error
    ExpFoo e = s.get(var);
    return e;
}

@Override
public boolean isVarFooFree() {
    // TODO
    return false;
}

@Override
public Set<VarFoo> getVarfoo() {
    return null;
}

@Override
public void collectVarfoo(Set<VarFoo> vars) {

}

@Override
public String toString() {
    return "" + value;
}

@Override
public boolean equals(Object o) {
    if (o == null) return false;
    if (!(o instanceof IntFoo))
        return false;
    if (o == this)
        return true;
    return value == (((IntFoo) o).value);
}

@Override
public int hashCode() {
    return Objects.hash(value);
}
}

标签: java

解决方案


对于第一个问题

我无法得到 times 和 bigTimes 的值。

根本原因在于TimesFoo#computeValue

@Override
    public int computeValue(Replacement subst) {
    return computeValue();
}

您完全忽略了该方法中的替换参数subst而只是调用computeValue(),因此您的变量永远不会被解析,因此出现错误UnsupportedOperationException: Cannot compute the value of a varfoo without a replacement!

对于第二个

我无法让 applyReplacement(repl) 工作。

根本原因在于PlusFoo#applyReplacement

@Override
    public ExpFoo applyReplacement(Replacement r) {
    return null;
}

你只是回到null那里,所以这就是你得到的。您需要将替换递归地应用于子表达式


推荐阅读