如何在不使用或getClass()实例的情况下检查对象的类型

时间:2015-09-26 02:24:56

标签: java oop design-patterns

示例情况: 我有一个电视抽象超类。两个子类继承自它。这两个子类都有工厂方法来创建自己的遥控器。 Remote是一个超类,它有两个子类。遥控器可以改变他们各自的电视频道(在这种情况下,三星遥控器应该与任何三星电视一起使用)。

远程类有一个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());
    }
}

2 个答案:

答案 0 :(得分:0)

一种可以确保来自通用API的共存类型层次结构的方法可以共享代码和该API但仍然只能与他们自己的特定实现一起使用marker interfacesgenerics

/**
 * 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...
    }

答案 1 :(得分:0)

工厂方法可以帮到你。来自GoF参考:

Factory Method pattern

将它应用于电视创建遥控器的地方:

Factory method applied to TV code

您不得在television方法上使用changeChannel()参数。这确实是您需要进行检查的原因。

这正是Collection.iterator()的工作原理。此外,Java API中没有记录许多具体的Iterator(它们是具体集合的内部类,请参阅How does the Java class ArrayList return an Iterator Object?)。

你可以在你的设计中采用类似的方法,并说遥控器的客户不需要知道它们是什么样的精确类,因为他们只是想用它们来改变频道。您可以使SamsungRemote成为SamsungTV的私有内部类,createRemote()方法始终返回一个上传类型的Remote。