1

I'm new to Java and I'm following along with Test Driven Development by Example. In chapter 8 we're exacting subclasses franc and dollar into Money. I've created the factory methods for franc and dollar like so but when I attempt to run the test I get "can not resolve symbol dollar" (or franc) for test lines:

Money five= new Money.dollar(5);
Money four= new Money.franc(5);

I've started over from scratch twice and tried googling it, but I'm not sure what I'm missing.

Money class:

public abstract class Money {

    abstract Money times(int multiplier);

    protected int amount;

    static Money dollar(int amount){
        return new Dollar(amount);
    }

    static Money franc(int amount){
        return new Franc(amount);
    }

    public boolean equals(Object object){
        Money money = (Money) object;
        return amount == money.amount
        && getClass().equals(money.getClass());
    }

}

Franc (Dollar is the same):

public class Franc extends Money {


    Franc(int amount){
        this.amount = amount;
    }

    Money times(int multiplier){
        return new Franc(amount * multiplier);
    }

}

Test:

import org.junit.Test;

import static org.junit.Assert.*;

public class MoneyTest {
    @org.junit.Test
    public void testMultplication(){
        Money five= new Money.dollar(5);
        assertEquals(new Dollar(10), five.times(2));
        assertEquals(new Dollar(15), five.times(3));
        Money four= new Money.franc(5);
        assertEquals(new Franc(10), four.times(2));
        assertEquals(new Franc(15), four.times(3));
    }

}
Charles
  • 379
  • 2
  • 14

2 Answers2

3
Money five= new Money.dollar(5);

is wrong syntax. Change it to:

Money five= Money.dollar(5);

because new keyword is used to create instances but you want to call a static method instead. Also an abstract class cannot be instantiated.

Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136
1

You're using a factory pattern; you don't need to use the new keyword at all.

Instead, use the factories:

Money five= Money.dollar(5);
Money four= Money.franc(5);

I would also encourage specificity with regard to your objects; one is a Dollar and the other is a Franc; you should use the instances of those instead of the more abstract Money. Not doing that would impact you if your subclasses were more evidently different (for instance, if Franc had a method to indicate which countries it was accepted in).

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • Thanks! I remember reading about constructors and abstract classes but now it should stick. – Charles Jan 03 '14 at 03:49
  • @Makoto - Amy IS using instances of `Dollar` and `Franc` - look at her code! – Dawood ibn Kareem Jan 03 '14 at 03:52
  • 1
    @DavidWallace: Look at what they're being stored in, though. Suppose `Franc` had a method that printed its value with respect to the dollar. How would you invoke that if it's only specific to that child method? – Makoto Jan 03 '14 at 03:53
  • If he read it right away I did have a typo that I fixed. Makoto was just really quick. – Charles Jan 03 '14 at 03:53
  • It's BETTER to use a less specific type for your variables. It tells future maintainers of your code that you're not going to use any Franc-specific or Dollar-specific methods. There are loads of questions about this point, here on SO. – Dawood ibn Kareem Jan 03 '14 at 03:55
  • @Makoto I see what you mean now. I'm following along with a book, so hopefully that will come up. – Charles Jan 03 '14 at 03:55
  • 1
    @Amy - it's unlikely that your book will give you the same advice as Makoto has. Have a look at http://stackoverflow.com/questions/1484445/why-are-variables-declared-with-their-interface-name-in-java for an idea as to why. – Dawood ibn Kareem Jan 03 '14 at 03:57
  • @DavidWallace: I think you're thinking more of interfaces than abstract classes. Your point is valid and holds well with interfaces, as you make compile-time contractual guarantees about what the underlying implementation will have available as methods. Your point falls apart with abstract classes (which is what this is), as the whole intention is for it to be extended, and the child classes be more specific than the parent. – Makoto Jan 03 '14 at 03:59
  • The same argument applies to both. It does not fall apart with abstract classes. The reason for HAVING an abstract class is basically the same as the reason for having an interface - except that you have the opportunity to code up some functionality that will be common to all the subclasses. If Amy follows your advice, it will bite her eventually. – Dawood ibn Kareem Jan 03 '14 at 04:01
  • @DavidWallace: In that case, experiment with it. Recreate this project, then give either class an extra method in it. Then try to invoke that from an instance of `Money`. If you can do this, then you should share how you were able to do that; I'd certainly love to know. – Makoto Jan 03 '14 at 04:04
  • That's exactly my point! Using the abstract class as the type GUARANTEES that some silly programmer is not going to try to do this. – Dawood ibn Kareem Jan 03 '14 at 04:05
  • @DavidWallace: Let's continue this [in chat](http://chat.stackoverflow.com/rooms/44371/private-chat), shall we? – Makoto Jan 03 '14 at 04:07
  • Continuing this would be a bit futile. Amy has a book. She should just follow the advice in her book. – Dawood ibn Kareem Jan 03 '14 at 04:13
  • I'm fine with agreeing to disagree at this point. No harm, no foul. – Makoto Jan 03 '14 at 04:14