继续创作,加速生长!这是我参加「日新计划 6 月更文应战」的第3天,点击查看活动详情

  • 本文主要介绍iOS规划方式中的笼统工厂办法。它和工厂办法有些类似,通常来说两个方式都用于相同的目的创立目标而不让客户端知晓回来了什么确切详细的目标。不同点话在于工厂办法是创立一种产品,经过子类创立并重载工厂办法以创立一种产品。而笼统工厂是经过组合目标的办法创立多系列产品,有必要修正父类的接口才干支撑新的产品。

1. 什么是笼统工厂

结合实践情况,比如咱们在餐厅吃披萨,通常咱们会有许多类型的披萨,比如有榴莲披萨,烤鸭披萨,火腿披萨,水果披萨等。咱们能够结合咱们不同的口味挑选不同的披萨,咱们消费者不在乎披萨是怎么做出来的,只要披萨好吃就行。
在软件规划中,假如客户端想手工创立一个类的目标,那么客户端需求首要知道这个类的细节。可是,一组相关的目标能够在运行时按不同的规范发明的不一样,此刻客户端就要知道悉数细节才干创立他们,能够经过笼统工厂处理这个问题。

笼统工厂:是一种创立型规划方式,供给一个创立一系列相关或相互依赖目标的接口,而无需指定其详细类。

2. 什么时候运用笼统工厂办法

软件规划的黄金规律:变动需求笼统
假如有多个类共有相同的行为,但实践完成不同,则可能需求某种笼统类型作为其父类被继承。笼统类型界说所有相关详细类将有的共同行为。比如,咱们知道一般的披萨时什么样子,在点餐的时候知道会端上来什么。咱们说”出去吃披萨吧“这儿,”披萨“便是一个笼统的类型,界说了披萨饼应该具有的共同特征,比如都是能够吃的,下面是圆形的饼上面是浇头。可是,咱们从不同的店能够得到同一种披萨(芝士火腿披萨)略有不同的风味。有不同类型的披萨,咱们简略的将其叫做“披萨”。来称呼这种特定类型的食物。
因此咱们界说出产一种披萨的进程,只是关于不同的店出产的进程略微不同,一起依据不同的类型,出产不同口味的披萨。这一进程咱们能够称为笼统工厂办法。这一进程通常会结合工厂办法,无需规划在运行时决定运用什么工厂的复杂机制。 阐明:当现有的笼统工厂需求支撑新产品时,需求向父类添加相对应的新工厂办法,这意味着也要修正其子类以支撑新产品的新工厂办法

3. Cocoa Touch结构中运用笼统工厂

之前咱们在工厂办法中说了NSNumber类关于工厂办法的运用阐明,实践上关于它的初始化不同类型的办法中

iOS设计模式之抽象工厂

除了boolNumber的实践类型时NSCFBoolean以外,绝大部分都是NSCFNumber类型,虽然回来的都是NSNumber详细子类的实例,可是都是支撑NSNumber公有接口

    NSNumber *boolNumber = [NSNumber numberWithBool:YES];
  NSNumber *charNumber = [NSNumber numberWithChar:'a'];
 
  NSLog(@"%d",[boolNumber intValue]);
  NSLog(@"%@",[charNumber boolValue] ? @"true" : @"fales");

打印成果为:

1
true

boolNumber内部保持的布尔值为YES,可是完成了公有的intValue办法,回来反映呢不布尔值的适当int值,charNumber内部也是,完成了公有的boolValue办法,回来反应其内部字符值“a”的布尔值。
接受不同类型参数回来NSNumber类工厂办法出产各种”数工厂“NSNumber中类工厂办法界说了决定实例化何种私有详细子类的默许行为,这种特色称为类簇。类簇是笼统工厂的一种方式NSNumber本身是一个高度笼统的工厂,而NSCFBoolean和NSCFNumber是详细工厂子类。子类是详细工厂

4.代码展示

import XCTest
/// The Abstract Factory protocol declares a set of methods that return
/// different abstract products. These products are called a family and are
/// related by a high-level theme or concept. Products of one family are usually
/// able to collaborate among themselves. A family of products may have several
/// variants, but the products of one variant are incompatible with products of
/// another.
protocol AbstractFactory {
    func createProductA() -> AbstractProductA
    func createProductB() -> AbstractProductB
}
/// Concrete Factories produce a family of products that belong to a single
/// variant. The factory guarantees that resulting products are compatible. Note
/// that signatures of the Concrete Factory's methods return an abstract
/// product, while inside the method a concrete product is instantiated.
class ConcreteFactory1: AbstractFactory {
    func createProductA() -> AbstractProductA {
        return ConcreteProductA1()
    }
    func createProductB() -> AbstractProductB {
        return ConcreteProductB1()
    }
}
/// Each Concrete Factory has a corresponding product variant.
class ConcreteFactory2: AbstractFactory {
    func createProductA() -> AbstractProductA {
        return ConcreteProductA2()
    }
    func createProductB() -> AbstractProductB {
        return ConcreteProductB2()
    }
}
/// Each distinct product of a product family should have a base protocol. All
/// variants of the product must implement this protocol.
protocol AbstractProductA {
    func usefulFunctionA() -> String
}
/// Concrete Products are created by corresponding Concrete Factories.
class ConcreteProductA1: AbstractProductA {
    func usefulFunctionA() -> String {
        return "The result of the product A1."
    }
}
class ConcreteProductA2: AbstractProductA {
    func usefulFunctionA() -> String {
        return "The result of the product A2."
    }
}
/// The base protocol of another product. All products can interact with each
/// other, but proper interaction is possible only between products of the same
/// concrete variant.
protocol AbstractProductB {
    /// Product B is able to do its own thing...
    func usefulFunctionB() -> String
    /// ...but it also can collaborate with the ProductA.
    ///
    /// The Abstract Factory makes sure that all products it creates are of the
    /// same variant and thus, compatible.
    func anotherUsefulFunctionB(collaborator: AbstractProductA) -> String
}
/// Concrete Products are created by corresponding Concrete Factories.
class ConcreteProductB1: AbstractProductB {
    func usefulFunctionB() -> String {
        return "The result of the product B1."
    }
    /// This variant, Product B1, is only able to work correctly with the
    /// variant, Product A1. Nevertheless, it accepts any instance of
    /// AbstractProductA as an argument.
    func anotherUsefulFunctionB(collaborator: AbstractProductA) -> String {
        let result = collaborator.usefulFunctionA()
        return "The result of the B1 collaborating with the ((result))"
    }
}
class ConcreteProductB2: AbstractProductB {
    func usefulFunctionB() -> String {
        return "The result of the product B2."
    }
    /// This variant, Product B2, is only able to work correctly with the
    /// variant, Product A2. Nevertheless, it accepts any instance of
    /// AbstractProductA as an argument.
    func anotherUsefulFunctionB(collaborator: AbstractProductA) -> String {
        let result = collaborator.usefulFunctionA()
        return "The result of the B2 collaborating with the ((result))"
    }
}
/// The client code works with factories and products only through abstract
/// types: AbstractFactory and AbstractProduct. This lets you pass any factory
/// or product subclass to the client code without breaking it.
class Client {
    // ...
    static func someClientCode(factory: AbstractFactory) {
        let productA = factory.createProductA()
        let productB = factory.createProductB()
        print(productB.usefulFunctionB())
        print(productB.anotherUsefulFunctionB(collaborator: productA))
    }
    // ...
}
/// Let's see how it all works together.
class AbstractFactoryConceptual: XCTestCase {
    func testAbstractFactoryConceptual() {
        /// The client code can work with any concrete factory class.
        print("Client: Testing client code with the first factory type:")
        Client.someClientCode(factory: ConcreteFactory1())
        print("Client: Testing the same client code with the second factory type:")
        Client.someClientCode(factory: ConcreteFactory2())
    }
}

执行成果

Client: Testing client code with the first factory type:
The result of the product B1.
The result of the B1 collaborating with the (The result of the product A1.)
Client: Testing the same client code with the second factory type:
The result of the product B2.
The result of the B2 collaborating with the (The result of the product A2.)

5. 总结

笼统工厂和工厂区别?
一个被其多个详细工厂类型共有的笼统工厂类型。抛开笼统,工厂通常指的是详细工厂,而且,它也没有工厂办法的意思。有时,一开始运用详细工厂,后边重构为运用多个详细工厂的笼统工厂。
笼统工厂咱们通常会运用协议去界说完成详细的产品,详细的类也便是详细工厂去完成这个产品。它能够涉及许多类型的目标创立,笼统工厂能够躲藏详细的创立进程,不为客户端所见。供给这种笼统,而不暴露创立进程中任何不必要的细节,或确切的类型