2

我为一家保险经纪人工作,我在这里实施的其中一件事是报价服务,该服务将客户的详细信息作为输入,并为许多保险公司提供报价列表作为响应。

它目前的工作方式如下:

  • 索引页面接收 JSON 字符串中的报价数据
  • 报价数据依次发送到每个保险公司的计算脚本 - 这些脚本在索引页面的数组中列出
    • 每个保险公司的计算都参考数据库表,以查看在保险开始日期的情况下应该使用哪组费率
    • 数据被发送到特定脚本并生成一个速率并返回给索引
  • 索引按升序对结果进行排序,并将它们作为 JSON 字符串返回给发送者

这个解决方案的问题是:

  • 难以测试 - 每组速率都是一个单一的代码块,因此不能单独测试各个部分
  • 难以维护 - 为保险公司添加一组新费率涉及将当前费率复制到新脚本,进行必要的更改,并在数据库表中使用新费率的开始日期创建新条目。这反过来导致:
  • 费率之间有很多代码重复

我新的部分形成的解决方案是有一个主Quoteservice类,它包含所有报价通用的功能,无论是保险公司还是产品Insurer1Insurer2等等。从索引页面调用的子类以获取报价率。这些反过来将具有每组费率(等)的子Insurer1May2012Insurer1July2012。我的问题在于试图摆脱对数据库表的需要来为开始日期选择正确的费率。

我想能够说

$quoteresults=array();
$quoteresults=array_merge(Insurer1->getQuote($quotedata), $quoteresults);
$quoteresults=array_merge(Insurer2->getQuote($quotedata), $quoteresults);

并让每个InsurerX对象根据开始日期使用正确的子类( 等) - 可能通过在其每个子类上调用一个函数InsurerXMay2012,该函数返回子类的费率生效时的日期(或时间戳)。不幸的是,在寻找循环遍历类的子类的最佳方法之后,这似乎不是最好的方法。InsurerXJuly2012getStartdate()

最终目标是能够只添加该类型Insurer1Sept2012的一个子类来更改速率,而不必更改多个文件和/或数据库表。(覆盖以前的费率不是一种选择 - 调整过程需要能够在它们被取代后长达 12 个月内获得费率)

我如何看待新版本的示例

abstract class Quoteservice
{
    // Various common functionality here...
}

class Insurer1 extends Quoteservice
{
    public function getQuote($quotedata)
    {
        $subclass=null;
        // This is the bit I'm not sure of...
        // Maybe something like:
        foreach($subclasses as $thissubclass)
        {
            $subclassstart=$thissubclass->getStartdate();
            // Ignore all start dates greater than proposed start date
            if($subclassstart < $quotedata['startdate'])
            {
                $subclasses[$subclassstart]=$thissubclass;
            }
        }
        ksort($subclasses);
        $subclass=array_pop($subclasses);
        return $subclass->getQuote()
    }
}

class Insurer1May2012 extends Insurer1
{
    public function getStartdate()
    {
        return 1335830400; // unix time stamp for 1st May 2012
    }

    public function getQuote($quotedata)
    {
        // Calculate May's rate here...

        return $quoteinfo;
    }
}

class Insurer1July2012 extends Insurer1
{
    public function getStartdate()
    {
        return 1341100800; // unix time stamp for 1st July 2012
    }

    public function getQuote($quotedata)
    {
        // Calculate July's rate here...

        return $quoteinfo;
    }
}
4

3 回答 3

1

尝试将其实现为单个 PHP 页面/脚本是行不通的。一旦你开始分离逻辑,其他一切都会变得简单得多。

报价数据依次发送到每个保险公司的计算脚本

我敢打赌,表演也很糟糕。

每组速率都是一个整体的代码块,因此不能单独测试各个部分

然后,作为最低限度,每个保险公司应该有一个 URL,这可以反过来实现到特定于该保险公司的其他 URL 的路由。当然,您将脚本实现为用于聚合 Web 服务的前端控制器。

似乎在寻找循环遍历类的子类的最佳方法之后

您似乎错过了面向对象编程的一个关键点 - 封装。

使用正确的子类(InsurerXMay2012 ....

天哪,不!

您混淆了代码和数据。难怪each set of rates is a monolithic block of code

可能通过在其每个子类上调用函数 getStartdate()

当您检查您的电子邮件时,您是否认为 POP 服务器会读取它保存的每封电子邮件,只是为了找到发给您的电子邮件?

虽然我相信最佳解决方案会将功能拆分为多个聚合 URL(即 HTTP 级别架构),并且路由应该由数据构造(即数据库)驱动,但很可能仅使用对象就可以在合理的系统中实现预期的结果面向 PHP。但是,除非您能够分离关注点、分层代码架构、分离代码和数据并锻炼如何正确地通过代码路由执行线程,否则您只会弄得一团糟的意大利面条代码。

于 2012-07-30T12:25:25.693 回答
0

虽然可以,但在类名中存储变量数据不是我推荐的方法。PHP 语言中已经有用于这种数据存储的内置结构。

我不会为每种报价类型的每个日期都设置一个子类,而是使用该类的构造函数来获取一个日期变量,它可以使用它来计算所需的报价。

例如:

class Insurer1 extends Quoteservice {
    public function __construct(DateTime $date) {
        // Do something with the data.
    }
}

// ... would be initialised like this:

$quoteResults = array();
$quoteResults[] = new Insurer1("2012-07-30");
$quoteResults[] = new Insurer2("2012-07-21");

该类Quoteservice可以实现诸如 的方法getStartDate(),这些方法可用于 的所有实例Quoteservice

您甚至可以完全消除对Insurer1, Insurer2... 类的需求,并将保险公司的名称作为另一个参数传递给构造函数。

$someQuote = new Quoteservice("2012-07-30", "Insurer1");
于 2012-07-30T11:18:58.377 回答
0

我认为不Insurer应该延长QuoteService。它们具有不同的(如果偶尔重叠)功能。QuoteService是 的聚合器InsuranceQuotesInsurer是一个提供者InsuranceQuoteInsuranceQuote取决于谁是谁,InsurerInsuree可能是谁。所以它可能会是这样的:

$client= new Insuree;
$quoter= new QuoteService;
$quoter->calculate($client);
$quoter->show_quotes();

像这样的类:

class Insuree {

  protected $age;
  protected $gender;
  protected $marital_status;
  protected $drivers_license;
  protected $address;
  //etc. with constructor and getters/setters
}

class Insurer {

  function get_quote(Insuree $client, $args=null) {
    //do stuff
   return $quote; //InsuranceQuote obj.
  }
}

class InsuranceQuote {
  protected $period;
  protected $total;
  //etc. with constructor, getters, setters

  function out(){
    //echo something
  }
}

class QuoteService {

  protected $insurers; //SplObjectStorage containing Insurer objects
  protected $quotes; //SplObjectStorage containing InsuranceQuote objects

  function __construct($args=null){
     $this->get_insurers($args);  //limit the list with $args if you like
     $this->quotes=new SPLObjectStorage;
  }

  protected function get_insurers($args){
    $this->insurers=new SPLObjectStorage;
    //access list of insurers from db(?)
    while($row = $list->fetch_assoc()){
       $i=new Insurer($list);
       $this->insurers->attach($i);
    }
  }

  function calculate(Insuree $client, $args=null) {
    foreach($this->insurers as $quoter){
      $this->quotes->attach($quoter->get_quote($client, $args));
    }
  }

  function show quotes(){
    foreach($this->quotes as $quote) $quote->out();
  }

}

关于如何子类Insurer化:每个特定的数据Insurer必须存储在某个地方。如果它可以以标准格式存储,那么您只需要一个Insurer类。设计表格来保存这些数据将是设计过程中最困难的部分。在不了解您的数据形状的情况下,我不想建议一种结构。

于 2012-07-30T12:52:10.607 回答