Design Pattern(0) - decouple and factory mode

1. 計算簡單的 expression:

以下程式碼使用scala:

import Calculator.*

import scala.io.StdIn.readLine

object Main {

    @main def m(args: String*) = {
        println("Input number A:")
        val a = readLine.toFloat

        println("Input number B:")
        val b = readLine.toFloat

        println("Input an operator:")
        val op = readLine.strip

        try {
            val operation = Operation.createOperator(op)
            operation.a = a
            operation.b = b
            println(operation.getResult)
        } catch {
            case e:Exception => println(e)
        }
    }
}
package Calculator

abstract class Operation(var a: Float, var b: Float) {
    def getResult:Float
}

class OperationAdd(_a: Float = 0, _b: Float = 0) extends Operation(_a, _b) {
    override def getResult: Float = a + b
}

class OperationSub(_a: Float = 0, _b: Float = 0) extends Operation(_a, _b) {
    override def getResult: Float = a - b
}

class OperationMul(_a: Float = 0, _b: Float = 0) extends Operation(_a, _b) {
    override def getResult: Float = a * b
}

class OperationDiv(_a: Float = 0, _b: Float = 1) extends Operation(_a, _b) {
    require(b != 0)
    override def getResult: Float = a / b
}

object Operation {
    def createOperation(op: String): Operation = {
        op match {
            case "+" => new OperationAdd()
            case "-" => new OperationSub()
            case "*" => new OperationMul()
            case "/" => new OperationDiv()
            case _ => throw IllegalArgumentException("Illegal Operation")
        }
    }
}
  1. 本篇主旨在於將程式碼解耦合。每個 OperationXXX 在程式中不互相影響,所以修復 Bug 或 Refactor 時不會影響其他元件的可用性。

  2. 子類別 _a 及 _b 是為了不遮蔽父類別的 var a 及 var b。

  3. 最後 createOperation 回傳各種 OperationXXX ,沒有正確初始化還是能呼叫 getResult 其實風險。


2. 匿名物件工廠模式:

透過滿足 trait 讓物件具有特定行為,再利用工廠產生匿名物件。

package Calculator

object Operation {

    def createOperation(op: String): MathOperation = {
        op match {
            case "+" => (_: Float) + (_: Float)
            case "-" => (_: Float) - (_: Float)
            case "*" => (_: Float) * (_: Float)
            case "/" => (_: Float) / (_: Float)
        }
    }
}

trait MathOperation {
    def getResult(a: Float, b:Float): Float
}

物件生成的細節封裝在 createOperation,運算的操作封裝在 getResult。使用時透過 createOperation 和 getResult 接口進行操作。

import Calculator.Operation.createOperation
import Cash.*

object Main {

    @main def m(args: String*) = {
        val operationAdd = createOperation("+")
        println(operationAdd.getResult(10, 20))

        val operationSub = createOperation("-")
        println(operationSub.getResult(10, 20))
    }
}

Reference:

1. 大話設計模式-程杰


留言

熱門文章