【问题标题】:JAVA Facade pattern, correct implementation?JAVA Facade模式,正确的实现?
【发布时间】:2018-08-11 18:36:26
【问题描述】:

我有一个客户端,它的构造函数在参数列表方面非常冗长,例如,

Class Client {
   private ServiceA _serviceA;
   private ServiceB _serviceB;
   ....
   private ServiceE _serviceE;

   public Client(ServiceA serviceA, ServiceB serviceB,...ServiceE service E) { ... }

   public doTask1(TypeA typeA) { //only serviceA, serviceB service being used... }

   public doTask2(TypeB typeB) { //only serviceD, serviceE being used ... }
}

我想在这里使用服务外观来修剪构造函数参数列表。但是,作为外观实现的核心责任,我很困惑。所以我写了一个外观,其中服务作为类变量及其 getter,如下所示:

Class Facade {
   private ServiceA _serviceA;
   private ServiceB _serviceB;
   ....
   private ServiceE _serviceE;

   getters () ...
}

在这种情况下,这是抽象外观的正确方法吗?如果不是,那么重构 Client 类的正确方法是什么?

【问题讨论】:

    标签: java oop service refactoring facade


    【解决方案1】:

    Facedes 具有完全不同的意图:创建它们是为了封装和隐藏类的底层结构和行为。以汽车为例。它由许多部件组成:车载电脑、燃油泵、发动机等。如果你想启动它,只需按下启动按钮:

    class FuelPump {
      private boolean pumpTurnedOn;
      public FuelPump() {
        pumpTunrnedOn=false;
      }
      public boolean isPumpTunredOn() {
        return pumpTurnedOn;
      }
      public void setPumpTurnedOn (boolean newState) {
        pumpTurndeOn=newState;
        if (newState) {
          System.out.println ("fuel pump now is on");
        } else {
          System.out.println ("fuel pump now is turned off");
        }
      }
    }
    

    class Engine {
      private boolean engineStarted;
      public Engine() {
        engineStarted=false;
      }
      public boolean isEngineStarted() {
        return engineStarted;
      }
      public void setEngineStarted (boolean newState) {
        engineStarted=newState;
        if (newState) {
          System.out.println("engine now is on");
        } else {
          System.out.println("engine now is turned off");
        }
      }
    }
    

    // this is the Car facade:
    class Car {
      private FuelPump fuelPump;
      private Engine engine;
      // + other components of Car
      public Car () {
        fuelPump = new FuelPump();
        engine = new Engine();
      }
      public void startCar() {
        fuelPump.setPumpTurnedOn(true);
        engine.setEngineStarted(true);
        // + other methods of start procedures with other components
        System.out.println("Your car has been startded");
      }
      public void stopCar() {
        engine.setEngineStarted(false);
        fuelPump.setPumpTurnedOn(false);
        // + other methods on other components for shutting down car
      }
    }
    

    客户端代码sn-p:

    Car car=new Car();
    car.startCar();
    // later on
    car.stopCar();
    

    正如您所见,客户端对启动汽车的底层组件一无所知。它只需要使用 startCar() 方法,其余的由 Car 门面完成。外观是一种结构模式。 如果您有许多构造函数参数并希望减少它们,请使用其中一种创建模式。如果您有必填和非必填字段,我建议使用 builder 模式。 例如,您的强制构造函数参数是 Service_A 和 Service_B 和 Service_C 到 Service_E 不是必需的。 那么你的 ClientBuilder 类应该是这样的:

    class ClientBuilder{
      private static Service_A serviceA;  // required
      private static Service_B serviceB;  // required
      private static Service_C serviceC;
      private static Service_D serviceD;
      private static Service_E serviceE;
    
      // since this builder is singleton
      private static ClientBuilder builderInstance = new ClientBuilder();
      private ClientBuilder () {};
    
      public static ClientBuilder getBuilderInstance (Service_A service_A, Service_B service_B){
        serviceA = service_A;
        serviceB = service_B;
        serviceC = null; 
        serviceD = null;
        serviceE = null;
        return builderInstance;
      }
    
      public static ClientBuilder addServiceC (Service_C service_C) {
        serviceC = service_C;
        return builderInstance; 
      }
    
      public static ClientBuilder addServiceD (Service_D service_D) {
        serviceC = service_D;
        return builderInstance; 
      }
    
      public static ClientBuilder addServiceE (Service_E service_E) {
        serviceE = service_E;
        return builderInstance; 
      }
    
      public static Client build(){
        return new Client (serviceA, ServiceB, ServiceC, ServiceD, ServiceE);
      }
    

    在这种情况下,您只能使用强制参数来实例化您的 Client 类。最好的事情是不需要的参数的顺序是可以互换的:

      Client aClient = ClientBuilder.getBuilderInstance(aServiceA, aServiceB)
            .addServiceE(aServiceE)
            .addServiceC(aServiceC)
            .build();
    

    现在已使用服务 A、B、C、E 创建了 aClient,而 serviceD 仍然为空。稍后您可以通过适当的设置器对其进行设置。 getter 和 setter 必须在您的 Client 类中。 简而言之,使用 builder 类,您可以减少仅用于强制的构造函数参数的数量,并稍后使用 setter 设置可选字段。 您可以在Gang of Four book 中阅读更多详细信息,或者如果您是认真的Java 爱好者,我建议您阅读Head First's Design Patterns 书。 希望能帮到你,再见!

    【讨论】:

      猜你喜欢
      • 2013-06-24
      • 2013-10-06
      • 2020-11-01
      • 2017-03-15
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      相关资源
      最近更新 更多