0

我对 OOP 很陌生,我担心我写的这个类设计得很糟糕。它似乎违反了 OOP 的几个原则:

  1. 它不包含自己的数据,但依赖于 yaml 文件获取值。
  2. 它的方法需要按特定顺序调用
  3. 它有很多实例变量和方法

但是,它确实有效。它很健壮,但每次添加页面元素时,我都需要修改源代码以添加新的 getter 方法

它是自动化测试套件中使用的 html 文档的模型。我一直在想一些方法可以放在子类中,但我担心我会有太多的类。

你怎么看?

class BrandFlightsPage < FlightSearchPage

  attr_reader :route, :date, :itinerary_type, :no_of_pax,
              :no_results_error_container, :submit_button_element

  def initialize(browser, page, brand)
    super(browser, page)

    #Get reference to config file
    config_file = File.join(File.dirname(__FILE__), '..', 'config', 'site_config.yml')

    #Store hash of config values in local variable
    config = YAML.load_file config_file

    @brand = brand        #brand is specified by the customer in the features file

    #Define instance variables from the hash keys
    config.each do |k,v|
      instance_variable_set("@#{k}",v)
    end

  end

  def visit
    @browser.goto(@start_url)
  end

  def set_origin(origin)
    self.text_field(@route[:attribute] => @route[:origin]).set origin
  end

  def set_destination(destination)
    self.text_field(@route[:attribute] => @route[:destination]).set destination
  end

  def set_departure_date(outbound)
    self.text_field(@route[:attribute]  => @date[:outgoing_date]).set outbound
  end

  def set_journey_type(type)
    if type == "return"
      self.radio(@route[:attribute]  => @itinerary_type[:single]).set
    else
      self.radio(@route[:attribute]  => @itinerary_type[:return]).set
    end
  end

  def set_return_date(inbound)
    self.text_field(@route[:attribute]  => @date[:incoming_date]).set inbound
  end

  def set_number_of_adults(adults)
     self.select_list(@route[:attribute]  => @no_of_pax[:adults]).select adults
  end

  def set_no_of_children(children)
    self.select_list(@route[:attribute]  => @no_of_pax[:children]).select children
  end

  def set_no_of_seniors(seniors)
    self.select_list(@route[:attribute]  => @no_of_adults[:seniors]).select seniors
  end

  def no_flights_found_message
    @browser.div(@no_results_error_container[:attribute] => @no_results_error_container[:error_element]).text
    raise UserErrorNotDisplayed, "Expected user error message not displayed" unless divFlightResultErrTitle.exists?
  end

  def submit_search
    self.link(@submit_button_element[:attribute] => @submit_button_element[:button_element]).click
  end
end
4

1 回答 1

0

如果这个类被设计成一个门面,那么它不是(太)糟糕的设计。它提供了一种连贯统一的方式来执行依赖于各种不相关行为持有者的相关操作。

关注点分离似乎很差,因为这个类本质上耦合了所有各种实现细节,这可能会变得有些难以维护。

最后,需要以特定顺序调用的事实方法可能暗示您正在尝试对状态机进行建模这一事实 - 在这种情况下,它可能应该分解为多个类(每个“状态”一个)。我不认为你会达到“太多方法”或“太多类”的点,事实是你需要每个类提供的特性是连贯的和有意义的。在哪里划线取决于您和您的特定实现的域要求。

于 2012-08-24T10:58:29.247 回答