2015-09-26 2 views
0

Пример ситуации: У меня есть телевизионный абстрактный суперкласс. Наследуются два подкласса. Оба этих подкласса имеют заводские методы для создания собственных пультов. Remote - это суперкласс, и он имеет два подкласса. Пульты могут менять свой канал на телевидении (в этом случае удаленный samsung должен работать с любым телевизором Samsung).Как проверить тип объекта без использования экземпляра или getClass()

Удаленные классы имеют метод changeChannel для телевидения и канала. Мой вопрос заключается в том, что я могу сохранить эту иерархию с помощью методов и параметров, которые она имеет в настоящее время, и не использовать условную логику для удаленного, чтобы иметь возможность изменять только канал собственной марки телевидения. Я предоставил код ниже.

import java.util.*; 

public abstract class Television{ 
    private int channel; 

    public abstract Remote makeRemote(); 

    public int getChannel(){ 
     return channel; 
    } 

    public void setChannel(int c){ 
     channel=c; 
    } 
} 

import java.util.*; 


public class SamsungTelevision extends Television{ 
    private int channel; 

    public Remote makeRemote(){ 
     return new SamsungRemote(); 
    } 

} 

import java.util.*; 


public class SonyTelevision extends Television{ 
    private int channel; 

    public Remote makeRemote(){ 
     return new SonyRemote(); 
    } 

} 

import java.util.*; 


public abstract class Remote{ 

    public abstract void changeChannel(Television t,int channel); 
} 

import java.util.*; 


public class SamsungRemote extends Remote{ 

    public void changeChannel(Television t,int channel){ 
     t.setChannel(channel); 
     System.out.println("Samsung: Channel has been switched"); 
    } 

} 

import java.util.*; 


public class SonyRemote extends Remote{ 

    public void changeChannel(Television t,int channel){ 
     t.setChannel(channel); 
     System.out.println("Sony: Channel has been switched"); 
    } 
} 

import java.util.*; 


public class Driver{ 
    public static void main(String[] args){ 
     Television t = new SamsungTelevision(); 
     Television t1 = new SonyTelevision(); 
     Remote r=t.makeRemote(); 
     r.changeChannel(t,35); 
     System.out.println("Samsung current channel: " + t.getChannel()); 
     r.changeChannel(t1,37); 
     System.out.println("Sony current channel: " + t1.getChannel()); 
    } 
} 
+0

* и не нужно использовать условную логику для пульта дистанционного управления, чтобы иметь возможность изменять только канал собственной марки телевидения *? № –

+0

Есть несколько способов, которыми вы могли бы это сделать. Вы ищете что-то, что может привести к ошибке во время компиляции, если вы передадите Телевидение другой марки? Насколько вам разрешено общаться с существующими классами? – augray

+0

Текущий код в порядке. Зачем вам нужна эта проверка? Если вы хотите узнать только className, из которого выполняется код, используйте один метод, который просто регистрирует: this.getClass(). GetSimpleName(); –

ответ

0

Один из способов обеспечить сосуществующие иерархии типа из общего API может можно разделить код &, что API, но все еще работают только со своими конкретными реализациями используют marker interfaces и generics:

/** 
* Different manufacturers can extend this interface 
* to ensure compile-time compatibility of their products while 
* using standard APIs that use generics for type safety. 
*/ 
public interface Manufacturer { 

} 

/** 
* This interface marks products created by Samsung. 
*/ 
public interface Samsung extends Manufacturer { 

} 

/** 
* This interface marks products created by Sony. 
*/ 
public interface Sony extends Manufacturer { 

} 

public abstract class Television<M extends Manufacturer>{ 
    private int channel; 

    //this ensures that a television only makes a remote 
    //by the same manufacturer 
    public abstract Remote<M> makeRemote(); 

    public int getChannel(){ 
     return channel; 
    } 

    public void setChannel(int c){ 
     channel=c; 
    } 
} 

public class SamsungTelevision extends Television<Samsung>{ 
    private int channel; 

    public Remote<Samsung> makeRemote(){ 
     return new SamsungRemote(); 
    } 

} 


public class SonyTelevision extends Television<Sony>{ 
    private int channel; 

    public Remote<Sony> makeRemote(){ 
     return new SonyRemote(); 
    } 

} 


public abstract class Remote<M extends Manufacturer>{ 

    //this ensures that a remote only works with a remote 
    //by the same manufacturer 
    public abstract void changeChannel(Television<M> t,int channel); 
} 


public class SamsungRemote extends Remote<Samsung>{ 

    public void changeChannel(Television<Samsung> t,int channel){ 
     t.setChannel(channel); 
     System.out.println("Samsung: Channel has been switched"); 
    } 

} 


public class SonyRemote extends Remote<Sony>{ 

    public void changeChannel(Television<Sony> t,int channel){ 
     t.setChannel(channel); 
     System.out.println("Sony: Channel has been switched"); 
    } 
} 

public class Driver{ 
    public static void main(String[] args){ 
     Television<Samsung> t = new SamsungTelevision(); 
     Television<Sony> t1 = new SonyTelevision(); 
     Remote<Samsung> r=t.makeRemote(); 
     r.changeChannel(t,35); 
     System.out.println("Samsung current channel: " + t.getChannel()); 

     //generates a compile time error because r is a samsung remote and 
     //t1 is a Sony TV 
     //r.changeChannel(t1,37); 
     //System.out.println("Sony current channel: " + t1.getChannel()); 
    } 
} 

Это хорошо, потому что это создает безопасность во время компиляции. Люди не могут даже случайно написать программу, которая будет нарушать ограничения совместимости с производителем.

И если вы хотите сделать что-то, что может работать с телевизорами любой марки, вы можете сделать это также:

public static <M extends Manufacturer> void doSomethingWithTVOfAnyMake(Television<M> tv){ 
     int myChannel = tv.getChannel(); 
     //do more stuff... 
    } 
+0

Хорошо, я вижу. Таким образом, используя generics и интерфейсы маркеров, во время компиляции вы можете определить, с чем должен работать класс. Если я попытаюсь использовать телевизор Samsung с удаленным Sony во время выполнения, тогда я получу ошибку, потому что эти два типа не должны работать вместе, как это определено во время компиляции. Это верно? –

+0

Почти. На самом деле приятно, что вы не можете использовать телевизор Samsung с пультом Sony, он даже не будет компилироваться. Попробуйте раскомментировать строку '//r.changeChannel (t1,37);' выше и затем скомпилировать - вы должны получить сообщение об ошибке. – augray

+0

Ну ладно, я вижу. Спасибо –

0

метод завод будет делать это для вас. Из ссылки GoF:

Factory Method pattern

Применяя его, где пульты дистанционного управления создаются телевизоры:

Factory method applied to TV code

Вы не должны использовать television аргумент о методе changeChannel(). Это действительно источник того, почему вам нужно делать проверки.

Именно так работает Collection.iterator(). Кроме того, многие конкретные Iterator s не документированы в Java API (они являются внутренними классами конкретной коллекции, см. How does the Java class ArrayList return an Iterator Object?).

Вы можете использовать подобный подход в своем дизайне и сказать, что клиентам пультов не нужно знать, какой именно класс они есть, поскольку они просто хотят использовать их для изменения каналов. Вы можете сделать SamsungRemote частным внутренним классом SamsungTV, а метод createRemote() всегда возвращает восходящий тип Remote.

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