In a nutshell: The simple factory pattern is to design a factory class to create different objects that perform different functions.

background

Suppose you now have a requirement to implement a computer console program in any object-oriented language that asks you to enter two numbers and operation symbols and get the result.

InputManager

The InputManager class provides the basic input methods that will be used in later calculation classes.

class InputManager {
    static func inputNumber(a) -> Float {
        print("Please enter a number:")
        let input = String(data: FileHandle.standardInput.availableData, encoding: .utf8)
        guard var string = input else { return 0 }
        string.removeLast()
        guard let number = Float(string) else { return 0 }
        return number
    }
    
    static func inputOperator(a) -> String {
        print("Please enter an operation symbol (+, -, *, /) :")
        let input = String(data: FileHandle.standardInput.availableData, encoding: .utf8)
        guard var string = input else { return "" }
        string.removeLast()
        return string
    }
}
Copy the code

Code V1.0

Here is the undesigned code. While the requirements are implemented, object-oriented thinking is not used, code specifications (variable names have no real meaning) and zero divisor exclusion are not followed.

static func calculate(a) {
    let a = InputManager.inputNumber()
    let char = InputManager.inputOperator()
    let b = InputManager.inputNumber()
    
    var result: Float = 0
    
    if char = = "+" {
        result = a + b
    } else if char = = "-" {
        result = a - b
    } else if char = = "*" {
        result = a * b
    } else if char = = "/" {
        result = a / b
    } else {
        print("Operator not correct!")
        return
    }
    print("result = \(result)")}Copy the code

Code V2.0

The computing classes and console code belong to different functional modules and should be decoupled from the logic, making coupling less desirable. Easy to expand and maintain. If you want to extend a new Operation, you can just add it to the Operation class, and the user doesn’t care about the implementation. If you want to implement computer functionality across different platforms, the Operation class can also be reused directly.

static func calculate(a) {
    let numberA = InputManager.inputNumber()
    let operatorChar = InputManager.inputOperator()
    let numberB = InputManager.inputNumber()
    
    let result = Operation.result(numberA, numberB, operatorChar)
    print("result = \(result)")}class Operation {
    static func result(_ numberA: Float._ numberB: Float._ operatorChar: String) -> Float? {
        var result: Float = 0
        
        if operatorChar = = "+" {
            result = numberA + numberB
        } else if operatorChar = = "-" {
            result = numberA - numberB
        } else if operatorChar = = "*" {
            result = numberA * numberB
        } else if operatorChar = = "/" {
            if numberB ! = 0 {
                result = numberA / numberB
            } else {
                print("The divisor cannot be zero!")
                return nil}}else {
            print("Operator not correct!")
            return nil
        }
        return result
    }
}
Copy the code

Code V3.0

Although the calculation classes are encapsulated in the 2.0 code, the respective calculation logic is not separated, which will result in the maintenance of only one calculation logic, such as addition, need to obtain all the calculation logic Operation class code to modify. You can then design a factory class that instantiates the computations needed. Logical code that does not require other operations to maintain and extend one operation. At the same time, object-oriented encapsulation, inheritance, polymorphic characteristics are used.

static func calculate(a) {
    let numberA = InputManager.inputNumber()
    let operatorChar = InputManager.inputOperator()
    let numberB = InputManager.inputNumber()

    let operate = OperationFactory.creatOperate(operatorChar)
    operate?.numberA = numberA
    operate?.numberB = numberB
    print("result = \(operate?.result())")}class OperationFactory {
    static func creatOperate(_ operatorChar: String) -> Operation? {
        var result: Operation?
        
        if operatorChar = = "+" {
            result = OperationAdd()}else if operatorChar = = "-" {
            result = OperationSubtract()}else if operatorChar = = "*" {
            result = OperationMultiply()}else if operatorChar = = "/" {
            result = OperationDivide()}else {
            print("Operator not correct!")
            return nil
        }
        return result
    }
}

class Operation {
    var numberA: Float = 0
    var numberB: Float = 0
    
    func result(a) -> Float? {
        fatalError("Must Override")}}class OperationAdd: Operation {
    override func result(a) -> Float? {
        return numberA + numberB
    }
}

class OperationSubtract: Operation {
    override func result(a) -> Float? {
        return numberA - numberB
    }
}

class OperationMultiply: Operation {
    override func result(a) -> Float? {
        return numberA * numberB
    }
}

class OperationDivide: Operation {
    override func result(a) -> Float? {
        if numberB = = 0 {
            print("The divisor cannot be zero!")
            return nil
        }
        return numberA / numberB
    }
}

Copy the code

UML class diagrams