创建正确的对象关系

时间:2018-05-16 11:17:47

标签: oop design-patterns

我开始学习OOP,我知道很难建立好的,高质量的,可测试的代码,而且我害怕犯一些架构错误而且开始因为后来很难重构。

目前,我正在研究Laravel,我需要一个组件(程序的一小部分)来计算在线广告统计(CPM,EPC等)uisng cronjob。为此,我需要从数据库中收集数据,计算统计数据并将其存储到相关表中。这需要使用cronjob通过CLI运行。应尽可能通过SQL来计算统计数据,但并不总是可以使用当前的体系结构来完成。 因此,我需要创建一些可重用的组件,可以使用新的stat计算逻辑轻松扩展,只需从DB中获取已经计算的逻辑并将其存储或获取,计算并存储到DB。并且有能力让futuhre在应用程序的任何部分轻松使用它,而不仅仅是CLI。

要从CLI运行它我正在使用带调度的Laravel命令:

class StatsComamnd extends Command
{
    protected $signature = 'project:calculatestats {statName}';
    public function __construct(StatsService $statsService){
        parent::__construct();
        $this->statsService = $statsService;
    }
    public function handle() {
        $method = $this->argument('statName');
        if(!method_exists($this, $method)) {
            $this->error('Invalid stat name provided!');
       }

       $this->{$method}();
    }
    public function networkOffers():void {
         $this->stastService->setStatsHandler(app(OffersNetworkStatsHandler::class))->handle();
    }
    public function networkOffersCpm():void{
         app(OffersNetworkCpmHandler::class)->handle(); 
    }
    public function networkOffersEpc:void{
         app(OffersNetworkEpcHandler::class)->handle(); 
    }
    public function networkSurveys():void{
         app(SurveysNetworkHandler::class)->handle(); 
    }
    public function networkSurveysCpm():void{    
         app(SurveysNetrworkCpmHandler::class)->handle(); 
    }
    public function networkSurveysEpc:void{
         app(SurveysNetworkEpcHandler::class)->handle(); 
    }
    //...other handlers, like countryOffersCpm, toolSpecificOffersCpm and so on
}

SurveysNetrworkCpmStatsHandler:

/** This handle responsible of collectiong, calculating and storing network wide survey CPMs. We can't calculate CPM inside DB, so here we are going to use CpmCalculator */
class SurveysNetrworkCpmStatsHandler implements StatsHandlerInterface {
    private $surveyImpressionsRepo;
    private $statsRepo;
    private $vcPointRepo;
    private $calculator;
    public function __construct(
        SurveyImpressionRepositoryInterface $surveyImpressionRepository,
        SurveyStatsRepositoryInterface $statsRepository,
        VcPointRepositoryInterface $vcPointRepository,
        CpmCalculator $calculator
    ){
        $this->surveyImpressionsRepo = $surveyImpressionRepository;
        $this->calculator = $calculator;
        $this->vcPointRepo = $vcPointRepository;
        $this->statsRepo = $statsRepository;
    }
    public function handle() {
        $stats = [];
        list($impressions, $conversions) = $this->fetchStatisticData();
        foreach ($impressions as $impression) {
            $sid = $impression->survey_id;
            $conversion = $conversions->first(function($conversion) use ($sid) {
                return $conversion->survey_id === $sid;
            });
            if(!isset($conversion)) {
                continue;
            }
            $stat = new \SurveyNetworkCpmStat();
            $stat->offer_id = $impression->offer_id;
            $stat->survey_id = $sid;
            $stat->mobile_cpm = $this->calculator->setConversionCount($conversion->conversions_count_mobile)->setImpressionsCount($impression->unique_impressions_count_mobile)->setPayoutSum($conversion->payout_sum_mobile)->calculate();
            $stat->desktop_cpm  = $this->calculator->setConversionCount($conversion->conversions_count_desktop)->setImpressionsCount($impression->unique_impressions_count_desktop)->setPayoutSum($conversion->payout_sum_desktop)->calculate();
            $stat[] = $stat->toArray();
        }
        $this->store($stats)
   }

   private function fetchStatisticData(){
       $impressions = $this->surveyImpressionsRepo->getImpressionsForNetworkCpm();
       $conversions = $this->vcPointRepo->getConversionsForSurveyNetworkCpm();

       return [$impressions, $conversions];
   }

   private function store($stst): bool{
       $this->statsRepo->insert()
   }
}

SurveysNetrworkStatsHandler:

/** This handle responsible of collectiong, calculating and storing all network wide survey stats.*/
class SurveysNetrworkStatsHandler implements StatsHandlerInterface {
    private $cpmHandler;
    private $epcHandler;
    private $statsRepo;
    public function __construct(
        SurveysNetrworkCpmStatsHandler $cpmHandler,
        SurveysNetrworkEpcStatsHandler $epcHandler,
        SurveyStatsRepositoryInterface $statsRepository
    ){
        $this->cpmHandler = $cpmHandler;
        $this->epcHandler = $epcHandler;
        $this->statsRepo = $statsRepository;
    }
    public function handle() {
        $this->cpmHandler->handle();
        $this->epcHandler->handle();
    }
}

OffersNetrworkCpmStatsHandler:

etrworkCpmStatsHandler:

/** This handle responsible of collectiong, calculating and storing network wide offers CPMs. We can calculate CPM inside DB, so here do not need any Calculator */
class OffersNetrworkCpmStatsHandler implements StatsHandlerInterface {
    private $surveyImpressionsRepo;
    private $statsRepo;
    public function __construct(
        SurveyImpressionRepositoryInterface $surveyImpressionRepository,
        SurveyStatsRepositoryInterface $statsRepository
    ){
        $this->surveyImpressionsRepo = $surveyImpressionRepository;
        $this->statsRepo = $statsRepository;
    }
    public function handle() {
        $stats = [];
        $stats =  $this->fetchStatisticData();
        $this->store($stats)
   }

   private function fetchStatisticData(){
       return $this->surveyImpressionsRepo->getCpm();
   }

   private function store($stst): bool{
       $this->statsRepo->insert()
   }
}

CpmCalculator:

/** Class NetworkCpmCalculator. This object responsible for calculation of CPM. Formula to calculate cpm is payout_sum/(impressions_count/1000) */
class NetworkCpmCalculator implements StatsCalculatorInterface {
    private $payoutSum = 0;
    private $impressionsCount = 0;
    private $conversionsCount = 0;
    public function setPayoutSum(float $payoutSum = null):self{
        $this->payoutSum = $payoutSum;
        return $this;
    }
    public function setImpressionsCount(int $impressionsCount = null):self{
        $this->impressionsCount = $impressionsCount;
        return $this;
    }
    public function setConversionCount(int $conversionsCount = null):self{
        $this->conversionsCount = $conversionsCount;
        return $this;
    }
    public function calculate():int{
        if(!$this->validate()) {
            return null;
       }
       return $this->payoutSum/($this->impressionsCount/1000);
    }
    //validation here
}

我在这里删除所有验证逻辑并接口到reduca数量的代码。

任何人都可以建议任何改进,也许我可以在这里使用一些模式?谢谢你的任何建议。

0 个答案:

没有答案