[英]Java: If-else instanceof extended classes
我有一個抽象類X
和一些對該類進行擴展的類,分別稱為A
, B
和C
在其他一些類Y
我有一些依賴於類類型的方法調用。 if-else語句如下所示:
public class Y implements InterfaceY {
public Y(){
}
public String doStuff (X x, Boolean flag) {
String s = "";
if (x instanceof A) {
doStuff((A) x));
} else if (x instanceof B) {
doStuff((B) x));
} else if (x instanceof C) {
doStuff((C) x, flag);
} else {
throw new Exeption();
}
return s;
private String doStuff(A a) {
return "";
}
private String doStuff(B b) {
return "";
}
private String doStuff(C c, Boolean flag) {
return "";
}
}
請注意,所有方法都具有相同的名稱( doStuff()
),但根據類(有時是標記)的不同,該方法的實現方式也不同。 當然,一旦從X擴展的分類增加,這看起來就很可怕,並且變得非常復雜。
我有什么辦法可以創建一個中間接口(或其他東西)來處理大多數(或全部)if-else語句?
首先,將這些方法從此處取出,並將它們分別放入A,B和C類中,以實現X接口。
private String doStuff(A a) {
return "";
}
private String doStuff(B b) {
return "";
}
private String doStuff(C c, Boolean flag) {
return "";
}
然后:
if (x instanceof A) {
doStuff((A) x));
} else if (x instanceof B) {
doStuff((B) x));
} else if (x instanceof C) {
doStuff((C) x, flag);
可以只是x.doStuff();
(你甚至不必須通過A,B,C,因為這將是this
里面的方法,標志,你必須惹根據更具體的您的代碼周圍。例如,其他2層doStuff
的方法可以也接受該標志,但忽略它)
方法1
使用狀態模式 。 它可以解決您的問題並消除if
和else
。
這是java示例 。
狀態模式將方法調用委托給實現相同接口但行為不同的對象。
狀態模式示例:
public class StatePatternExample {
public static void main(String[] args) {
Girlfriend anna = new Girlfriend();
// OUTPUT
anna.kiss(); // *happy*
anna.greet(); // Hey, honey!
anna.provoke(); // :@
anna.greet(); // Leave me alone!
anna.kiss(); // ...
anna.greet(); // Hey, honey!
}
}
interface GirlfriendInteraction extends GirlfriendMood {
public void changeMood(GirlfriendMood mood);
}
class Girlfriend implements GirlfriendInteraction {
private GirlfriendMood mood = new Normal(this);
public void provoke() {
mood.provoke();
}
public void kiss() {
mood.kiss();
}
public void greet() {
mood.greet();
}
public void changeMood(GirlfriendMood mood) {
this.mood = mood;
}
}
interface GirlfriendMood {
public void provoke();
public void kiss();
public void greet();
}
class Angry implements GirlfriendMood {
private final GirlfriendInteraction context;
Angry(GirlfriendInteraction context) { // more parameters, flags, etc. possible
this.context = context;
}
public void provoke() {
System.out.println("I hate you!");
}
public void kiss() {
System.out.println("...");
context.changeMood(new Normal(context));
}
public void greet() {
System.out.println("Leave me alone!");
}
}
class Normal implements GirlfriendMood {
private final GirlfriendInteraction context;
Normal(GirlfriendInteraction context) {
this.context = context;
}
public void provoke() {
System.out.println(":@");
context.changeMood(new Angry(context));
}
public void kiss() {
System.out.println("*happy*");
}
public void greet() {
System.out.println("Hey, honey!");
}
}
如您所見,“ Girlfriend
”類沒有if
和else
。 看起來很干凈。
“ Girlfriend
”類對應於您的abstract class X
,“ Normal
和“ Angry
”類對應於A
, B
和C
然后,您的Y
類將直接委托給X,而無需檢查任何情況。
方法2
使用命令模式 。 然后,您可以將命令對象移交給Y
的doStuff()
方法,然后執行它。
如何實現Handler
接口,然后按支持的類型映射它:
public interface Handler<T extends X>{
Class<T> supportedClass;
void doStuff(T value, Object...args);
}
public class Y implements InterfaceY {
private Map<Class<?>, Handler<?>> handlers;
public Y(List<Handler<?>> handlers){
// populate map
}
public void process(X value){
handler.get(value.getClass).doStuff(X, ...);
// you would have to figure out how to determine when other values are needed
}
}
雙重派遣怎么辦?
class X {
public String letYdoStuff(Y y, Boolean flag) {
return y.doStuff(this, flag);
}
public static void main(String [] args) {
//X x = new A();
X x = new B();
Y y = new Y();
y.doStuff(x, false);
}
public X getThis() {
return this;
}
}
class A extends X {
public String letYdoStuff(Y y, Boolean flag) {
return y.doStuff(this, flag);
}
}
class B extends X {
public String letYdoStuff(Y y, Boolean flag) {
return y.doStuff(this, flag);
}
}
class C extends X {
public String letYdoStuff(Y y, Boolean flag) {
return y.doStuff(this, flag);
}
}
class Y {
public Y(){
}
public String doStuff (X x, Boolean flag) {
String s = "";
return x.letYdoStuff(this, flag);
}
public String doStuff(A a, Boolean flag) {
System.out.println("in A");
return "";
}
public String doStuff(B b, Boolean flag) {
System.out.println("in B");
return "";
}
public String doStuff(C c, Boolean flag) {
System.out.println("in C");
return "";
}
}
這可能是一個困難的問題。 我認為Cruncher的解決方案是在合適的情況下將doStuff
添加到X並在A
, B
, C
覆蓋它, A
是最簡單,最好的解決方案。 但是,由於單一責任原則 ,它並不總是合適的。 (我認為這是正確的術語。如果我對某些術語有誤,我深表歉意,我對所有術語都不完全是最新的。)
這個想法是,你並不一定doStuff
到X
,如果它有無關的目的X
。 如果X
和Y
是同一個“團隊”的一部分,即它們都已被設置為滿足一個特定應用程序的目的,那么可能就可以了。
但是,假設你有一個抽象的Shape
有子類Circle
, Square
, Undecagon
, RandomBlob
等方面將是在屬於一些方法Shape
類,這將是到使用的任何應用Shape
類。 但是現在說您正在編寫一個使用其中某些形狀的游戲,並且您想要一個多態操作,該操作確定當飛猴吃掉該形狀時會發生什么。 即使該類是您自己創建的,也不在其他人的庫中,您也不想在Shape
類中添加抽象的computeEatenByFlyingMonkey
方法,因為這對於通常用於其他用途的類而言太具體了這個游戲。
我可以想到幾種解決方法。
如果不適合(或不可能)將doStuff
添加到X
,但是如果A
, B
和C
與您的應用程序聯系更緊密,那么將doStuff
添加到它們是適當的,則可以添加另一個類:
public abstract class XWithStuff extends X {
// repeat any constructors in X, making them all be just
// calls to super(...)
public abstract void doStuff (Boolean flag);
}
public class A extends XWithStuff {
@Override
public void doStuff (Boolean flag) { ... }
}
以此類推。 ( XWithStuff
只是一個示例名稱;在現實生活中,同時包含“ X”和對應用程序或用途的一些引用的名稱可能會更好。)(PS我不知道為什么您使用Boolean
而不是boolean
但是如果有充分的理由,我將以這種方式離開。)
如果也不合適或不可能將doStuff
添加到A
, B
和C
,則可能的解決方法是:
public interface StuffInterface {
public void doStuff (Boolean flag);
}
public class AWithStuff extends A implements StuffInterface {
@Override
public void doStuff (Boolean flag) { ... }
}
然后在程序中創建類AWithStuff
對象而不是A
,等等。要在X
上調用doStuff
:
void doStuff (X x, Boolean flag) {
if (x instanceof StuffInterface) {
((StuffInterface) x).doStuff (flag);
} else {
throw new IllegalArgumentException ();
}
}
如果這不是一個選擇,並且您必須直接處理A
, B
等,並且不能將doStuff
添加到這些類中,那么任何解決方案都將有點笨拙。 如果您不希望使用if
- then
- else
,則可以查看訪客模式 ,或者可以想象創建一個HashMap<Class<?>,Interf>
來映射A.class
, B.class
等。到調用正確的doStuff
某些接口對象。 但是我還沒有弄清楚細節。 (實際上,除非您具有某種由X類型的對象組成的復雜結構,否則“訪客模式”可能不合適。)
分開DoStuffOperation
,創建相對工廠並使用它們。
public interface DoStuffOperation<T> {
String doStuff(T x);
}
public class ADoStuffImpl implements DoStuffOperation<A> {
public String doStuff(A x) {
return "doStuff<A>";
}
}
public class ADoStuffWithFlagImpl implements DoStuffOperation<A> {
public String doStuff(A x) {
return "doStuffWithFlag<A>";
}
}
public class DoStuffImplFactory {
public final static <T extends X> DoStuffOperation<X> getDoStuff(Class<T> xClass,boolean flag) {
DoStuffOperation<X> impl = null;
if(xClass.equals(A.class))
{
if(flag)
impl = (DoStuffOperation)new ADoStuffWithFlagImpl();
else
impl = (DoStuffOperation)new ADoStuffImpl();
}
}
return impl;
}
}
public class Y implements InterfaceY {
public String doStuff (X x, Boolean flag) {
return DoStuffImplFactory.getDoStuff(x.getClass(),flag).doStuff(x);
}
}
這樣,您不必重構對Y.doStuff()
或X
和派生類的調用。 除非X
類實現了DoStuffCreator接口,否則您根本無法刪除任何instanceof
來決定使用哪種doStuff()
實現:
interface DoStuffCreator {
DoStuffOperation getDoStuffOperation(boolean flag);
}
X
和A
是您的課程。 您還可以使用反射或其他自動方式(外部屬性文件等)進行構造。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.