代码是如何变得抽象?

作者: Lupino | 来源:发表于2018-07-31 23:04 被阅读49次

从简单的代码开始,慢慢的迭代,经过几次变得抽象复杂起来。
本文将以定时任务系统 worker 的演化过程来说明代码是如何变得抽象。

第一次迭代

module Worker2 where

import Prelude

import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work)

periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}

someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)

main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
  addFunc "func1" do
    n <- name
    liftAff $ someFunc1 n
    done

  work 10

第二次迭代

module Worker2 where

import Prelude

import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work, JobT)

periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}

someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)

someFunc2 :: String -> Aff Unit
someFunc2 _ = delay (Milliseconds 1000.0)

affTask :: (String -> Aff Unit) -> JobT Aff Unit
affTask f = do
  n <- name
  liftAff $ f n
  done

main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
  addFunc "func1" $ affTask someFunc1
  addFunc "func2" $ affTask someFunc2

  work 10

func1func2 是差不多类似的函数所以我们抽象出 affTask

第三次迭代

affTask 目前只能适用 String -> Aff Unit 类型的函数,
但实际上我们会有很多相类似的函数,如 Int -> Aff Unit
我们需要对 affTask 进行改造,让它适用。

module Worker2 where

import Prelude

import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work, JobT)
import Data.Maybe (Maybe (..))
import Data.Int (fromString)

periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}

someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)

someFunc2 :: String -> Aff Unit
someFunc2 _ = delay (Milliseconds 1000.0)

someFunc3 :: Int -> Aff Unit
someFunc3 _ = delay (Milliseconds 1000.0)

mkAffTask :: forall a. (String -> Maybe a) -> (a -> Aff Unit) -> JobT Aff Unit
mkAffTask mk f = do
  n <- mk <$> name
  case n of
    Nothing -> done
    Just n0 -> do
      liftAff $ f n0
      done

affTask :: (String -> Aff Unit) -> JobT Aff Unit
affTask = mkAffTask Just

affTaskI :: (Int -> Aff Unit) -> JobT Aff Unit
affTaskI = mkAffTask fromString

main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
  addFunc "func1" $ affTask someFunc1
  addFunc "func2" $ affTask someFunc2
  addFunc "func3" $ affTaskI someFunc3

  work 10

mkAffTask 就是用来构造 affTaskaffTaskI 这两个函数。

第四次迭代

如果我们的函数需要在过一段时间在执行一个呢?

module Worker2 where

import Prelude

import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work, JobT, schedLater)
import Data.Maybe (Maybe (..))
import Data.Int (fromString)

periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}

someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)

someFunc2 :: String -> Aff Unit
someFunc2 _ = delay (Milliseconds 1000.0)

someFunc3 :: Int -> Aff Unit
someFunc3 _ = delay (Milliseconds 1000.0)

someFunc4 :: String -> Aff (Maybe Int)
someFunc4 _ = pure $ Just 10

someFunc5 :: Int -> Aff (Maybe Int)
someFunc5 _ = pure Nothing

mkAffTask :: forall a b. (b -> JobT Aff Unit) -> (String -> Maybe a) -> (a -> Aff b) -> JobT Aff Unit
mkAffTask finish mk f = do
  n <- mk <$> name
  case n of
    Nothing -> done
    Just n0 -> do
      r <- liftAff $ f n0
      finish r

maybeLater :: Maybe Int -> JobT Aff Unit
maybeLater Nothing = done
maybeLater (Just v) = schedLater v

affTask :: (String -> Aff Unit) -> JobT Aff Unit
affTask = mkAffTask (const done) Just

affTaskI :: (Int -> Aff Unit) -> JobT Aff Unit
affTaskI = mkAffTask (const done) fromString

affLaterTask :: (String -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTask = mkAffTask maybeLater Just

affLaterTaskI :: (Int -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTaskI = mkAffTask maybeLater fromString

main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
  addFunc "func1" $ affTask someFunc1
  addFunc "func2" $ affTask someFunc2
  addFunc "func3" $ affTaskI someFunc3
  addFunc "func4" $ affLaterTask someFunc4
  addFunc "func5" $ affLaterTaskI someFunc5

  work 10

第五次迭代

如果我们的数据不是从 name 来获取呢?

module Worker2 where

import Prelude

import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work, JobT, schedLater, workload)
import Data.Maybe (Maybe (..))
import Data.Int (fromString)

periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}

someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)

someFunc2 :: String -> Aff Unit
someFunc2 _ = delay (Milliseconds 1000.0)

someFunc3 :: Int -> Aff Unit
someFunc3 _ = delay (Milliseconds 1000.0)

someFunc4 :: String -> Aff (Maybe Int)
someFunc4 _ = pure $ Just 10

someFunc5 :: Int -> Aff (Maybe Int)
someFunc5 _ = pure Nothing

mkAffTask :: forall a b. (b -> JobT Aff Unit) -> (String -> Maybe a) -> JobT Aff String -> (a -> Aff b) -> JobT Aff Unit
mkAffTask finish mk get f = do
  n <- mk <$> get
  case n of
    Nothing -> done
    Just n0 -> do
      r <- liftAff $ f n0
      finish r

maybeLater :: Maybe Int -> JobT Aff Unit
maybeLater Nothing = done
maybeLater (Just v) = schedLater v

affTask_ :: JobT Aff String -> (String -> Aff Unit) -> JobT Aff Unit
affTask_ = mkAffTask (const done) Just

affTask :: (String -> Aff Unit) -> JobT Aff Unit
affTask = affTask_ name

affTaskI_ :: JobT Aff String -> (Int -> Aff Unit) -> JobT Aff Unit
affTaskI_ = mkAffTask (const done) fromString

affTaskI :: (Int -> Aff Unit) -> JobT Aff Unit
affTaskI = affTaskI_ name

affLaterTask_ :: JobT Aff String -> (String -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTask_ = mkAffTask maybeLater Just

affLaterTask :: (String -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTask = affLaterTask_ name

affLaterTaskI_ :: JobT Aff String -> (Int -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTaskI_ = mkAffTask maybeLater fromString

affLaterTaskI :: (Int -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTaskI = affLaterTaskI_ name

main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
  addFunc "func1" $ affTask someFunc1
  addFunc "func2" $ affTask someFunc2
  addFunc "func3" $ affTaskI someFunc3
  addFunc "func4" $ affLaterTask someFunc4
  addFunc "func5" $ affLaterTaskI someFunc5
  addFunc "func6" $ affTask_ workload someFunc1
  addFunc "func7" $ affTaskI_ workload someFunc3
  addFunc "func8" $ affLaterTask_ workload someFunc4
  addFunc "func9" $ affLaterTaskI_ workload someFunc5

  work 10

总结

经过五次迭代我们构造出一个非常复杂的 mkAffTask 函数。

相关资源:

相关文章

  • 代码是如何变得抽象?

    从简单的代码开始,慢慢的迭代,经过几次变得抽象复杂起来。本文将以定时任务系统 worker 的演化过程来说明代码是...

  • 优雅地使用ListView--一句代码定制Adapter

    前言 如何高效并简洁的使用listview,首先自然是关心如何对BaseAdapter定制。站在代码抽象的角度,子...

  • Android高效并简约的使用ListView(一)

    前言 如何高效并简洁的使用listview,首先自然是关心如何对BaseAdapter定制。站在代码抽象的角度,子...

  • 抽象类和抽象方法

    抽象类是包含抽象方法的类,而抽象方法不包含任何可实现的代码,只能在其子类中实现抽象函数的代码。 子类继承父类的成员...

  • 零散专题35 AST抽象语法树.md

    什么是抽象语法树 抽象语法树(abstract syntax tree,AST,或者简称语法树)是源代码的抽象语法...

  • Java语言中抽象类和接口的定义及其使用

    学习目的 学习掌握抽象类和接口的定义及其使用,如何测量代码的执行效率。 相关技术、及其使用 抽象类(abstrac...

  • 设计模式 - 抽象工厂+反射

    有些代码是伪代码,运行不起来。 一、概述 抽象工厂:ProductA 和 ProductB 都是两个抽象的产品,之...

  • AST

    抽象语法树 抽象语法树(Abstract Syntax Tree)简称 AST ,是源代码的抽象语法结构的树状表现...

  • 抽象语法树(AST)与acron

    什么是抽象语法树(AST) AST是源代码语法结构的一种抽象表示,它以树状的形式表现程序代码; 什么是acron ...

  • [Python设计模式] 04 - 代理模式

    需求变更应该尽早发现,发现的越早代码的抽象越容易,等到业务逻辑变得庞大复杂,已有代码已经到处在使用时,重构的成本就...

网友评论

    本文标题:代码是如何变得抽象?

    本文链接:https://www.haomeiwen.com/subject/btekvftx.html