2013-06-19 3 views
2

У меня есть такие классы:Java наиважнейшая абстрактный метод проектирования стратегия

abstract class Person{void toDrink(Liquid l);} 

class Liquid{} 
class Alcohol extend Liquid{} 
class Milk extends Liquid{} 


class Adult extends Person{void toDrink(Liquid l){}} 
class Child extends Person{void toDrink(Liquid l){}} 

Я хочу ребенок и взрослые не принимать жидкости, как аргументы, но молоко и алкоголь соответственно, но я должен переопределить абстрактный метод с точно Жидким аргументом. Поэтому, когда я пишу

Person child = new Child(); 
child.toDrink(new Alcohol()); 

ребенок может принимать алкоголь в качестве аргумента для питья. Я могу решить эту проблему, используя Исключения, или если(), но я прошу вас советовать мне лучший дизайн для этих отношений. Я хочу это, когда я передаю неправильный аргумент методу toDrink() (от алкоголя до ребенка или молока для взрослых), моя IDE подчеркивает это как ошибку и ошибку компиляции, когда я пытаюсь запустить ее.

+2

немного от темы, но: if 'toString()' превращает объект в строку, что делает 'toDrink()' do? –

+0

Во-первых: добро пожаловать в StackOverflow. На ваш вопрос: если вы хотите, чтобы IDE обрабатывала эту абстракцию, не требуется, потому что тогда расширение не будет возможным. Вы используете только «абстрактный класс», если вы ничего не знаете об этом во время компиляции. –

+0

вы можете использовать instanceof здесь, чтобы проверить, на каком экземпляре он фактически указывает. – tejas

ответ

1

Вы можете создать, как показано ниже?

abstract class Person<T extends Liquid>{ 
    void toDrink(T l) { 

    } 
} 

В приведенной выше коде, вы связывание метода toDrink() принять тип, который расширяет Liquid

class Adult<T extends Alcohol> extends Person<T>{ 

    void toDrink(T l){ 

    } 
} 

class Child<T extends Milk> extends Person<T>{ 
    void toDrink(T l){ 

    } 
} 

В приведенной выше коде, вы привязки toDrink() из Adult и Child метода, чтобы принять типа, который распространяется на Alcohol и Milk соответственно.

Теперь, в соответствии с вами ожидания ниже код не удается (с ошибкой компиляции)

Person<Milk> child = new Child<Milk>(); 
    child.toDrink(new Alcohol()); // error here 

, но это работает

child.toDrink(new Milk()); 
+0

Спасибо! Но я должен явно писать тип приемлемого напитка при создании Человека. Есть ли способ ускользнуть? – ka4eli

1

вы можете использовать дженерики, чтобы решить эту:

я бы предложить создать класс между Liquid и Milk:

public abstract class NonAlcoholicLiquid extends Liquid {} 
public class Milk extends NonAlcoholicLiquid {} 

и изменить ваши классы Person respectivly

public abstract class Person<Drink extends Liquid> { 
    void doDrink(Drink drink) { 

    } 
} 


public class Adult<Drink extends Liquid> extends Person<Drink> { 
    void doDrink(Drink drink){ 

    } 
} 

public class Child<Drink extends NonAlcoholicLiquid> extends Person<Drink> { 
    void doDrink(Drink drink){ 

    } 
} 

Таким образом, дети могут пить только безалкогольные жидкости, в то время как взрослые по-прежнему разрешено пить молоко;)

Update:

В соответствии с вашими комментарий, мы можем пропустить дженерики на данный момент:

public abstract class Person { 
    public abstract void doDrink(Liquid drink); 
} 


public class Adult extends Person { 
    void doDrink(Liquid drink) { 
     if(!(drink instanceof Alcohol)) { 
      throw new InvalidDrinkException("Adults may only drink Alcohol"); 
     } 
     // do the adult's drinking stuff 
    } 
} 

public class Child extends Person { 
    void doDrink(Liquid drink){ 
     if(!(drink instanceof Milk)) { 
      throw new InvalidDrinkException("Children may only drink Milk"); 
     } 
     // do the child's drinking stuff 
    } 
} 

Но у вашего подхода есть недостаток в мышлении: когда ребенок растет, экземпляр такой же, но класс должен будет измениться ...

+0

Спасибо! Но взрослым не разрешают пить молоко)) И настоящая проблема заключается в том, когда мы создаем экземпляр Child through Person, мы можем применить к нему метод todrink с алкоголем. Person child = new Child(); child.toDrink (новый Alcohol) - не ошибка компиляции, но ClassCasstException. И мы могли бы работать с объектами через их ссылки на суперклассы. – ka4eli

+0

@ ka4eli обновил мой ответ –

+0

Да, как я уже упоминал в моем вопросе, мы можем решить эту проблему, используя «if» и exceptions. Я думаю, что это не лучший дизайн, поэтому я разместил этот вопрос. Но, возможно, нет подходящих ответов, хотя ваши варианты с дженериками довольно хороши. Спасибо! – ka4eli

0

I want Child and Adult not to take Liquid as args but Milk and Alcohol respectively означает Взрослые напитки только Алкоголь и только ребенок Молоко. Таким образом, вы можете использовать generics с типом Liquid, который каждый тип напитка подтипа Person является параметром типа.

abstract class Person<L extends Liquid> { 
void toDrink(L l) { 
    //implementation here. 
} 
} 

class Liquid{} 
class Alcohol extend Liquid{} 
class Milk extends Liquid{} 

class Adult extends Person<Alcohol>{ 
    // You don't necessarily need to override the toDrink method. 
} 

class Child extends Person<Milk>{ } 

Вам не нужно переопределить метод toDrink() в каждом подклассе. У вас может быть только одна реализация в абстрактном классе Person.

+0

Это не работает, если мы пишем: Person p = new Child(); p.toDrink (новый алкоголь()); Он работает только тогда, когда мы создаем ссылку типа Child – ka4eli

+0

@ ka4eli. Если вы хотите объявить 'p' как' Person', то во время компиляции вы не можете убедиться, что его метод 'toDrink (l)' примет правильный аргумент , Причина в том, что компилятор не знает, какой тип 'Person'' p'. – nakosspy

+0

@ ka4eli Вы можете добавить проверку типа аргумента в реализацию методов 'toDrink (l)' 'Adult' и' Person'. Но тогда вы просто выбросите «RuntimeException», если 'l' был неправильного типа. Вы получаете тот же результат (ClassCastException) с моим подходом. Разница в том, что вам не нужно писать код проверки типа. – nakosspy

 Смежные вопросы

  • Нет связанных вопросов^_^