编辑代码

import java.util.*;

public class OptionExample {

    


    // Dan Grossman, CSE341, Programming Languages
// Lecture 22, Stage C: OOP vs. Functional Decomposition 

// we implement addition over any combination of two ints, strings, or 
// rationals using double dispatch

static abstract class Exp {
    abstract Value eval(); // no argument because no environment
    abstract String toStrng(); // renaming b/c toString in Object is public
    abstract boolean hasZero();
    abstract Exp noNegConstants();
}

static abstract class Value extends Exp {
    abstract Value add_values(Value other); // first dispatch
    // we /could/ name the next 3 methods add thanks to Java's static
    // overloading.  Doing so is the common style, but it makes the code look
    // less like the Ruby code and makes the code more difficult to talk about
    abstract Value add(Int other); // second dispatch
    abstract Value add(MyString other); // second dispatch
    abstract Value add(Rational other); // second dispatch

    Value eval() {
	return this;
    }
}

static class Int extends Value {
    public int i;
    Int(int i) {
	this.i = i;
    }
    String toStrng() {
	return "" + i;
    }
    boolean hasZero() {
	return i==0;
    }
    Exp noNegConstants() {
	if(i < 0)
	    return new Negate(new Int(-i));
	else
	    return this;
    }
    Value add_values(Value other) {
	return other.add(this);
    }
    Value add(Int other) {
	return new Int(other.i + i);
    }
    Value add(MyString other) {
	return new MyString(other.s + i);
    }
    Value add(Rational other) {
	return new Rational(other.i+other.j*i,other.j);
    }
}

static class MyString extends Value {
    public String s;
    MyString(String s) {
	this.s = s;
    }
    String toStrng() {
	return s;
    }
    boolean hasZero() {
	return false;
    }
    
    Exp noNegConstants() {
	return this;
    }

    Value add_values(Value other) {
	return other.add(this);
    }
    Value add(Int other) {
	return new MyString("" + other.i + s);
    }
    Value add(MyString other) {
	return new MyString(other.s + s);
    }
    Value add(Rational other) {
	return new MyString("" + other.i + "/" + other.j + s);
    }
}

static class Rational extends Value {
    int i;
    int j;
    Rational(int i, int j) {
	this.i = i;
	this.j = j;
    }
    String toStrng() {
	return "" + i + "/" + j;
    }
    boolean hasZero() {
	return i==0;
    }
    Exp noNegConstants() {
	if(i < 0 && j < 0)
	    return new Rational(-i,-j);
	else if(j < 0)
	    return new Negate(new Rational(i,-j));
	else if(i < 0)
	    return new Negate(new Rational(-i,j));
	else
	    return this;
    }
    Value add_values(Value other) {
	return other.add(this);
    }
    Value add(Int other) {
	return other.add(this);	// reuse computation of commutative operation

    }
    Value add(MyString other) {
	return new MyString(other.s + i + "/" + j);
    }
    Value add(Rational other) {
	int a = i;
	int b = j;
	int c = other.i;
	int d = other.j;
	return new Rational(a*d+b*c,b*d);
    }
}

static class Negate extends Exp {
    public Exp e;
    Negate(Exp e) {
	this.e = e;
    }
    Value eval() {
	// we downcast from Exp to Int, which will raise a run-time error
	// if the subexpression does not evaluate to an Int
	return new Int(- ((Int)(e.eval())).i);
    }
    String toStrng() {
	return "-(" + e.toStrng() + ")";
    }
    boolean hasZero() {
	return e.hasZero();
    }
    Exp noNegConstants() {
	return new Negate(e.noNegConstants());
    }
}

static class Add extends Exp {
    Exp e1;
    Exp e2;
    Add(Exp e1, Exp e2) {
	this.e1 = e1;
	this.e2 = e2;
    }
    Value eval() {
	return e1.eval().add_values(e2.eval());
    }
    String toStrng() {
	return "(" + e1.toStrng() + " + " + e2.toStrng() + ")";
    }
    boolean hasZero() {
	return e1.hasZero() || e2.hasZero();
    }
    Exp noNegConstants() {
	return new Add(e1.noNegConstants(), e2.noNegConstants());
    }
}

static class Mult extends Exp {
    Exp e1;
    Exp e2;
    Mult(Exp e1, Exp e2) {
	this.e1 = e1;
	this.e2 = e2;
    }
    Value eval() {
	// we downcast from Exp to Int, which will raise a run-time error
	// if either subexpression does not evaluate to an Int
	return new Int(((Int)(e1.eval())).i * ((Int)(e2.eval())).i);
    }
    String toStrng() {
	return "(" + e1.toStrng() + " * " + e2.toStrng() + ")";
    }
    boolean hasZero() {
	return e1.hasZero() || e2.hasZero();
    }

    Exp noNegConstants() {
	return new Mult(e1.noNegConstants(), e2.noNegConstants());
    }
}   


    public static void main(String[] args) { 
        Value a = new Int(5);
        Value b = new Int(6);
        System.out.println(new Add(a,b).eval().toStrng());
    }


}