美文网首页
设计模式:建造者模式

设计模式:建造者模式

作者: 闹鬼的金矿 | 来源:发表于2021-08-25 20:19 被阅读0次

    前一篇博客主要讲了工厂方法和抽象工厂用来创建对象的模式,这一篇主要来讲一下建造者模式。再讲它的结构之前,先举一个实际的例子用来说明一种常见的问题。

    比如在有些业务场景下,当你需要创建一个对象的时候,这个对象可能需要初始化的属性比较多。这个时候init方法的参数就会比较混乱,在实际进行初始化的地方比较容易出现错误,比如参数A可能传成了传成参数B。出现这种情况一是参数多,而是部分参数是可以传nil的,有时候会出现各种排列组合的情况。这种情况下,可能实际上这个对象是可以被拆分成不同的类型的对象,然后通过建造者模式来创建它,而不是同一在一个初始化方法里实现。

    建造者模式的结构:


    建造者模式.png

    对于某个具体的Build,它包含了多个方法,每个方法实现这个产品某一部分零件或者功能的代码。Director它依赖的是Builder,它的具体作用是通过传入的Builder,按特定的顺序调用Builder内的方法。而对于需求Client方来说,它需要根据实际的需求,生成相应的Builder并把它传给对应的Director。由Director来按步骤来调用Builder的方法,最后需求方通过Builder来获取具体的产品。可以理解为,比如说Director提供了ConstructA,ConstructB, ContructC 三个方法,每个方法都会构建出不同的产品ProductA, ProdcutB, ProductC, 需求方需要给Director传BuilderA,BuilderB, BuidlerC, 所以实际上 ConstrutX ,BuilderX,ProductX是对应起来的。

    看一个实际的代码例子:

    protocol BuilderProtocol {
        func reset()
        func setSeats(count: Int)
        func setEngine(engine: String)
        func setColor(color: String)
    }
    
    enum Builder {
        
        class BMWCar {
            
            var seats: Int;
            var engine: String;
            var color: String;
            
            init() {
                self.seats = 0;
                self.engine = "";
                self.color = "";
            }
            
            func printSelf() {
                print("MBW一台: \(self.seats)个座位,\(self.engine)发动机,颜色\(self.color)");
            }
        }
        
        class BMWBuilder: BuilderProtocol {
            
            var car:BMWCar;
            
            init() {
                self.car = BMWCar();
            }
            
            func reset() {
                self.car = BMWCar();
            }
            
            func setSeats(count: Int) {
                self.car.seats = count;
            }
            
            func setEngine(engine: String) {
                self.car.engine = engine;
            }
            
            func setColor(color: String) {
                self.car.color = color;
            }
            
            func product() -> BMWCar {
                return self.car;
            }
        }
        
        class Audi {
            var seats: Int;
            var engine: String;
            var color: String;
            
            init() {
                self.seats = 0;
                self.engine = "";
                self.color = "";
            }
            
            func printSelf() {
                print("Audi一台: \(self.seats)个座位,\(self.engine)发动机,颜色\(self.color)");
            }
        }
        
        class AudiBuilder: BuilderProtocol {
            
            var car: Audi;
            
            init() {
                self.car = Audi();
            }
            
            func reset() {
                self.car = Audi();
            }
            
            func setSeats(count: Int) {
                self.car.seats = count;
            }
            
            func setEngine(engine: String) {
                self.car.engine = engine;
            }
            
            func setColor(color: String) {
                self.car.color = color;
            }
            
            func product() -> Audi {
                return self.car;
            }
            
        }
        
        class Director {
            
            var builder: BuilderProtocol?
            
            init() {
                
            }
            
            func makeBMW(b: BMWBuilder) {
                self.builder = b;
            }
            
            func makeAudi(b: AudiBuilder) {
                self.builder = b
            }
            
            func productBMW() {
                self.builder?.reset();
                self.builder?.setSeats(count: 2);
                self.builder?.setEngine(engine: "4缸");
                self.builder?.setColor(color: "白色");
            }
            
            func productAudi() {
                self.builder?.reset();
                self.builder?.setSeats(count: 4);
                self.builder?.setEngine(engine: "6缸");
                self.builder?.setColor(color: "黑色");
            }
        }
    }
    
    func builder() {
        let d = Builder.Director();
        let ab = Builder.AudiBuilder();
        d.makeAudi(b: ab);
        d.productAudi();
        let audi = ab.product();
        audi.printSelf();
        
        let bmwB = Builder.BMWBuilder();
        d.makeBMW(b: bmwB);
        d.productBMW();
        let bmw = bmwB.product();
        bmw.printSelf();
    }
    

    考虑一下文章最开始的问题,可能是N种排列组合,那么Director可能是N个Contrcut方法。这种情况还是会特别复杂,比如构建一个网络请求的时候,像请求参数1, 请求方法2,重试次数3,压缩编码4,超时时间5,参数格式6,这是通常会考虑的变量。并且传参数的方式get/post就不太一样,如果通过director去封装这个构建的过程,如果只有那么几种常见的情况比如get/post,其他变量都是一样,那么问题不大。但是如果在调用方需求可能差别比较大,这个时候就需要调用方自己去取代Director构建自己的网络请求了,这个时候对于Builder就只需要一个具体类型,不需要对它进行抽象了。

    另外还需要考虑写出更加优雅的代码,可以考虑链式语法,最后的方式应该是:

    buidler = Network.method(.post).format(.json).params({"a": 1}).retry(3).timeout(10).build();
    builder.api_response(data, error){
      
    };
    

    Reference: Dive into design patterns

    相关文章

      网友评论

          本文标题:设计模式:建造者模式

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