2010-07-14 59 views
4

我有一個抽象類A和它的幾個實現。我期望通過添加更多的實現來隨着時間的推移而發展。哪種設計模式允許基於運行時類型的功能抽象?

我也有一個接口,在上面的類層次結構的實例(例如打印它們)做一些事情。

我希望接口的實現爲A的某些子類提供一些特殊功能,併爲其餘的子類提供默認功能。

我希望這個例子闡明事情:

abstract class A { } 
class B extends A { } 
class C extends A { } 

interface Processor { 
    public void process(A a); 
} 

class SimpleProcessor implements Processor { 

    //I want this to be called when argument is instance of A or C or any 
    //new class that will be added in the future 
    public void process(A a) { 
     //Line 14 
     System.out.println("Default processing"); 
    } 

    //I want this to be called when argument is instance of B 
    public void process(B b) { 
     System.out.println("Special processing"); 
    } 

} 

public class Runner { 

    public static void main(String[] args) { 
     B b = new B(); 
     Processor p = new SimpleProcessor(); 
     p.process(b); 
    } 

} 

的示例打印 「默認處理」。問題是要執行的方法是根據接口方法的編譯時類型來選擇的。有沒有一種方法(或設計模式),使這個程序打印「特別處理」,而不在第14行加入

if (a instance of B) 
    process((B) a); 

列表爲每一個需要特別處理類?

我看了一下visitor模式,但它看起來沒有什麼改進,因爲我不想用A的每個子類的方法「污染」處理器接口,因爲會添加更多的A子類。

換一種方式,我想接口的實現:

  • 提供的
  • 具體子類的方法的自定義實現提供了將在被添加類的默認實現未來
  • 避免列出所有的類在一個大的if-then-else的列表

謝謝!

+0

你正在尋找的模式被稱爲「可覆蓋的方法」... – 2010-07-14 10:58:11

+0

策略模式? – 2010-07-14 13:27:37

+0

謝謝大家的回覆。我最終使用了if-then-else語句測試的例子列表。 – idrosid 2010-07-15 08:00:57

回答

3

如果您創建一個適配器,接受要處理的對象並返回該對象的處理器,那麼該怎麼辦?

if A -> return ProcessorA 
if B -> return ProcessorB 

代碼例如:

class Adapter { 

    Processor getProcessor(Object o) { 
     if (o instance of A) { 
      return new ProcessorA(); 
     } else if ... 
    } 

} 
+0

感謝您的回覆。我正在考慮類似的東西。創建一個AbstractProcessor實現,該實現已爲A的每個子類重載方法,並使用if-then-else語句創建入口方法。在如果我可以有明確的轉換到A的特定子類的內部。因此,處理器的子類可以處理新類型的A,並且我可以添加處理器而不需要對A或子類進行任何更改。但是我擔心的是,看起來不像OO那樣擁有巨大的if-then-else塊來測試類型。我想知道是否有更好的方法。 – idrosid 2010-07-14 11:06:38

+0

你可以把屬性文件或XML映射,然後你就不會有一個大的if-then-else列表。或者...讓我嘗試先編碼它... – nanda 2010-07-14 11:21:46

+0

+1適配器是比擴展主類和使用簡單的polymorfism更好的選擇,因爲它有助於保持「服務」代碼(記錄,打印,繪圖,.. )出主班。 – 2010-07-14 11:38:26

4

移動代碼分成而變化,並使用多態性的類型。見Open Closed Principle

interface Processable { 
    void process(); 
} 

abstract class A implements Processable { 
    public void process() { 
     System.out.println("Default processing"); 
    } 
} 
class B extends A { 
    public void process() { 
     System.out.println("Special processing"); 
    } 
} 
class C extends A { 
    // default implementation inherited from A 
} 


class SimpleProcessor { 
    public void process(Processable p) { 
     p.process() 
    } 
} 

public class Runner { 
    public static void main(String[] args) { 
     B b = new B(); 
     Processor p = new SimpleProcessor(); 
     p.process(b); 
    } 
} 
+0

感謝您的回覆。 問題是我想有很多處理器實現。 爲了使事情更具體,A類是一個UI小部件,Processor是這些小部件的渲染器。我希望能夠添加更多渲染器(例如更多皮膚)。我還想添加更多的小部件(通過繼承現有的小部件),並且只能更新一些渲染器。 因此,A和處理器的兩個子類都有所不同,所以您建議的方法不能解決問題。 – idrosid 2010-07-14 11:00:08

+2

問題在於,您必須在類別中放置大量「服務」代碼,這些代碼不應該關注這些服務(日誌記錄,打印,繪圖等)。使用適配器非常靈活,並使「服務」代碼不在主要類中。 – 2010-07-14 11:37:09

0

這是使用Adapter的進一步改進。這種解決方案需要思考圖書館來源:http://code.google.com/p/reflections/

優勢:

  • 沒有如果再用的instanceof其他
  • 沒有配置

缺點:

  • 需要思考圖書館
  • 可以在一開始是緩慢

這是它:

import java.lang.reflect.ParameterizedType; 

public abstract class Processor<T> { 

    private final Class<T> processedClass; 

    public Processor() { 
     ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass(); 
     processedClass = (Class<T>) parameterizedType.getActualTypeArguments()[0]; 
    } 

    public Class<T> getProcessedClass() { 
     return processedClass; 
    } 

    protected abstract void process(T message); 

} 

public class A { 

} 

public class B { 

} 

public class ProcessorA extends Processor<A> { 

    @Override 
    protected void process(A message) { 
     System.out.println("Processing object A"); 
    } 

} 

public class ProcessorB extends Processor<B> { 

    @Override 
    protected void process(B message) { 
     System.out.println("Processing object B"); 
    } 

} 

import java.lang.reflect.Constructor; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
import java.util.Set; 

import org.reflections.Reflections; 

public class Adapter { 

    private Map<Class<?>, Processor<Class<?>>> mapping = new HashMap<Class<?>, Processor<Class<?>>>(); 

    public Adapter() throws Exception { 
     Reflections r = new Reflections(""); 
     Set<Class<? extends Processor>> subTypesOf = r.getSubTypesOf(Processor.class); 

     for (Iterator iterator = subTypesOf.iterator(); iterator.hasNext();) { 
      Class<? extends Processor> c = (Class<? extends Processor>) iterator.next(); 
      Constructor<? extends Processor> constructor = c.getConstructor(); 
      Processor p = constructor.newInstance(); 
      mapping.put(p.getProcessedClass(), p); 
     } 
    } 

    public <T> Processor<T> getProcessor(T obj) { 
     return (Processor<T>) mapping.get(obj.getClass()); 
    } 
} 

public class Main { 

    public static void main(String[] args) 
      throws Exception { 
     Adapter adapter = new Adapter(); 

     A a = new A(); 

     adapter.getProcessor(a).process(a); 

     B b = new B(); 

     adapter.getProcessor(b).process(b); 
    } 

} 

結果:

14:01:37.640 [main] INFO org.reflections.Reflections - Reflections took 375 ms to scan 4 urls, producing 222 keys and 919 values 
Processing object A 
Processing object B 
1

您可以讓類本身返回處理器

interface Widget { 
    Processor getProcessor(); 
} 
interface Processor { 
    void process(Widget w); 
} 
abstract class WidgetA implements Widget { 
    Processor getProcessor() { 
     return new Processor() { 
     void process(Widget w) {// do magic default process stuff} 
     }; 
    } 
} 
class WidgetB extends WidgetA { 
    // uses default processor 
} 
class WidgetC extends WidgetA { 
    Processor getProcessor() { 
     return new Processor() { 
     void process(Widget w) {// do magic widget C process stuff} 
     }; 
    } 
} 

然而對於不同的皮膚故事,也許它會更好創建一個處理器工廠,取決於部件返回合適的處理器,爲不同的皮膚,那麼你可以創建ProcessorFactory取決於其皮膚使用

interface ProcessorFactory { 
    Processor getWidgetAProcessor(); 
    .... 
} 



abstract class WidgetA implements Widget { 
    Processor getProcessor() { 
     return factory.getWidgetAProccesor(); 
    } 

    void setProcessorFactory(ProcessorFactory pf) { 
     this.factory = pf; // move method signature also to interface 
    } 
} 

注:這只是一個想法,肯定不是最好的解決辦法我認爲

1

如何爲每個對象創建Processor實現,然後將它們註冊到CompositeProcessor中,例如

public class ProcessorB implements Processor 
{ 
    public void process(A input) { // do something here for B. } 
} 
public class ProcessorC implements Processor 
{ 
    public void process(A input) { // do something here for C} 
} 
// add more processors if needed 

public class CompositeProcessor implements Processor 
{ 
    private Map<Class,Processor> processors; 
    public CompositeProcessor(Map<Class,Processor> processors) 
    { 
      this.processors=processors; 
    } 
    public void process(A input) 
    { 
      for (Map.Entry<Class<?>,Processor> entry : processors.entries()) 
      { 
       if (entry.getKey().isAssignableFrom(input.getClass()) 
       { 
        entry.getValue().process(input); 
        return; 
       } 
      } 
      // do default processing here 
    } 
} 

現在在Runner類中使用CompositeProcessor。

注意:我沒有編譯上面的代碼,只是在這個編輯器中輸入,因此可能會出現一些錯誤,但是您有想法:)。

一些優點是: - 處理器與其處理的類分離(例如A和ProcessorA分開)。 - 可能有多於1個處理器的給定對象 - 處理器的映射可以在運行時更改

0

模板方法。

基類實現默認行爲,派生類實現特定的行爲。

Class BaseWithTemplateMethod { 
    void process() { 
    // Default behavior goes here 
    } 
} 

Class DerivedWithSpecific extends BaseWithTemplate { 
    @override 
    void process() { 
    // Specific behavior goes here 
    } 
} 

你可以做到這一點的主題很多變化,比如在另一個類封裝的行爲,在運行時配置的情況下,爲他們使用的具體行爲,實質上是使用組成代替。這在Java和沒有多重繼承的其他語言中特別有用。