0

在我的项目中,我看到这样的界面。所有模型都扩展了接口。我想知道有什么用?

public interface IModel {

     <T> T modelTo(Class<T> clazz);
}

public interface IPerson extends IModel {

    public String getFirstName();

    public void setFirstName(String firstName);

    public String getMiddleName();

    public void setMiddleName(String middleName);

}

然后在代码中的某些地方我看到像

@Override
    public void modelJoin(IModel parent, IModel sample) {
      //Some code
      IPerson sample= sample.modelTo(IPerson.class);
      IPerson person = parent.modelTo(IPerson.class);

      //Some code

   }

你能解释一下它的洞察力吗?

4

3 回答 3

2

它看起来像使用适配器模式。这个想法是在给定另一个类的情况下创建一个类的“视图”,或者调整一种类型的类来充当另一个类。

一个简单的现实世界示例可以是电源插座。在不同的国家,使用不同类型的插座。因此,您使用适配器将手机插入通常无法“识别”的电源插座。

当然,这也可以使用面向对象编程和适配器模式来建模。使用您的 IModel 接口但将其命名为 IAdaptable 它可以像这样使用。

public interface IAdaptable {
    <T> T adaptAs(Class<T> clazz);
}
public interface IChargeAmerican { void chargePhoneInAmerica(); }
public interface IChargeEurope { void chargePhoneInEurope(); }

public class EuropeanSocket implements IAdaptable, IChargeEurope {
    public <T> T adaptAs(Class<T> clazz) {
        if (clazz.equals(IChargeAmerican.class)) {
            return new EuropeanSocketToAmericanSocketAdapter(this);
        }
        throw new RuntimeException("unknown");
    }

    public void chargePhoneInEurope() {
        ;
    }
}

public class AmericanSocket implements IChargeAmerican {
    public void chargePhoneInAmerica() {
         ;
    }
}

public class EuropeanSocketToAmericanSocketAdapter implements IChargeAmerican {
    private EuropeanSocket socket;
    public EuropeanSocketToAmericanSocketAdapter(EuropeanSocket socket) {
         this.socket = socket;
    }

    public void chargePhoneInAmerica() {
         socket.chargePhoneInEurope();
    }
}

要使用它,只需将欧洲插座适应美国插座,有点像在两者之间插入适配器。

public void foo() {
    EuropeanSocket europe = new EuropeanSocket();
    IChargeAmerican murica = europe.adaptAs(IChargeAmerican.class);
    murica.chargePhoneInAmerica();
}

此示例显示了 adaptAs 方法如何在 IChargeAmerican 和 IChargeEurope 两个接口之间创建链接。即使它们没有任何共同点,适配器也可以像它们那样工作。

现在,EuropeanSocket 实现了 IAdaptable 接口,以便将自己“转换”为另一个已知的套接字。通常尽管班级不应该对此负责。正如 wikipedia 上的示例所示,工厂或供应商更适合于此。

于 2013-08-08T12:35:09.623 回答
1

我想你问为什么方法签名

<T> T modelTo(Class<T> clazz);

用来。

该参数clazz用于实现方法内部的类型信息。然后,您可以非常轻松地访问类型信息。

然后,您可以创建一个对象并从具有给定类的已实现方法中返回它。

方法签名看起来有点笨拙,但很有帮助,因为编译后缺少通用信息(类型擦除),并且参数使您可以访问类型信息(以及预期的返回类型)。

于 2013-08-08T11:45:56.270 回答
0

我可以想象它可能已经通过传递一个 Class 对象作为调用 modelTo(Class clazz) 方法的其他方法的参数来允许类型转换,或者换句话说:让其他方法将 IModel 对象转换为任何类,甚至没有知道他们将把它转换成哪个类(甚至没有什么能阻止将 Class 实例传递给这个甚至不是 IModel 的子类型的方法......)

知道这个 modelTo 方法是如何实现的会很有趣。抽象骨架类中是否有单一的最终实现?它如何响应错误(例如将 null 作为 clazz 参数传递,或触发 ClassCastException)?换句话说:这可能是尝试将所有类转换封装到一个方法中,用自定义异常或类似的东西替换 ClassCastExceptions 吗?(ClassCastException 是一个 RuntimeException,它可能是一种确保抛出检查异常的方法,而不是在代码中的任何地方强制执行显式异常处理,我已经看到使用这种方法的项目......)

于 2013-08-08T12:19:49.020 回答