从封装变化的角度看设计模式对象创建

57次阅读

共计 14890 个字符,预计需要花费 38 分钟才能阅读完成。

封装变动之对象创立

在对象创立的过程中,常常会呈现的一个问题就是通过显示地指定一个类来创建对象,从而导致紧耦合。这是因为创建对象时指定类名将使你受特定实现的束缚而不是特定接口的束缚。这会使将来的变动更加简单。要防止这种状况,就应该间接地创建对象。

这种紧耦合的问题很大水平是由 new 关键字带来的,因为 new 的紧耦合呈现,使得紧耦合的类很难独立地被复用,因为它们之间是相互依赖的。并且紧耦合产生单块的零碎,要扭转或者删掉一个类,就必须要了解和扭转其余许多类。这也是导致系统难以保护和移植的一个重要起因。

所以能够通过“对象创立”模式绕开 new,从而防止在对象创立(new)过程中所导致的紧耦合(依赖具体的类),以此反对对象创立的稳固。

那么如何防止 new 呢?举个例子!

    public void fun1(){
        //...
        Product p = new Product(); // 改为:Product p = productFactory.createProduct();
        //...
    }

这样的形式就是通过一个工厂调用一个办法来创立相应的产品,然而可能大家又会产生一个问题,这样操作尽管解决了 Product 的 new 操作,然而对于 ProductFactory 而言不是也须要通过 new 来产生吗?

对于这个问题,我想是很多人在接触到设计模式的时候都会去思考的问题,既然 ProductFactory 还是要用到 new,那工厂类还有存在的必要吗?这时,咱们能够会想到两种解决形式,一是将 createProdyct() 办法写成静态方法,这样调用的时候天然不须要 new 了。二是通过注入的形式,比方在利用类当中通过 setter 或是构造方法传入一个工厂类的对象。

对于静态方法而言,简略地说,即便是应用静态方法,那 Product p = ProductFactory.createProduct() 这样仍然是一种紧耦合的形式,因为工厂类无奈替换,和间接 new 出产品区别不大。

对于注入形式,大家更多的是纳闷,既然能够传入一个工厂类对象,那为什么不间接传入相应的产品,不是更简略间接吗?当然不是的,首先须要明确的是,工厂类的作用是作为一个笼子,这个笼子须要帮忙咱们解放住‘将来的变动’,要晓得一个产品的变动可能总是大于工厂的变动。在这种状况下,举出一个最简略的例子,你在编码的过程中,可能会用到不只一个产品,那你就可能须要很多 setter 或者批改构造方法;然而如果这些产品都能够通过这个工厂来获取,是不是就相当于用笼子关住了变动,使其在一个范畴中跳动。

在学习设计模式时,永远要记住的一句话就是“设计模式是用来教会咱们如何应答将来可能的变动”。如果你可能确定本人的零碎将来没有变动,那天然用不到设计模式;或者你的零碎将来全是变动,那也用不到设计模式,设计模式做的就是隔离稳固与变动,如果没有稳固,那就用不到设计模式。

‘new’是一种硬编码,到底’硬‘在那里,同样一个简略的理由,如果将来构造方法发生变化或者说结构参数减少(缩小),而在源码中有很多中央都是通过 new 来获取实例对象,找到并批改源码将会是一项很大的工作。

在解决这样的“对象创立”问题中就有工厂办法、形象工厂、原型模式和建造者模式等相干设计模式。

工厂办法(Factory Method)

  1. 用意

    定义一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod 使得一个类的实例化提早到其子类。

  2. 实例

    Factory Method 绝对于简略工厂而言,齐全遵循了“不改代码”的准则,然而其应用情景相比形象工厂应用条件没有那么高,因而能够说是应用最多的创立型模式之一了。

    思考这样一个利用,它能够向用户显示多种文档,比方 word、pdf、txt 等等。在这个框架中,首先,想到的可能就是利用简略工厂模式。

    public interface Document{public void open();
        public void close();
        public void save();
       // ......
    }
    public class PdfDocument implements Document{
        @Override
        public void open(){
            //open pdfDocument code
            System.out.println("open pdf!");
        }
    
        @Override
        public void close() {System.out.println("close pdf!");
        }
    
        @Override
        public void save() {System.out.println("save pdf!");
        }
       // ......
    }
    public class TxtDocument implements Document{
        //Txt 实现代码, 同 PdfDocument
        ......
    }
    public class DocumentFactory{public Document createDocument(String type){if(type=="pdf"){return new PdfDocument();
            }else if(type=="txt"){return new TxtDocument();
            }else {return null;}
        }
    }
    // 简略工厂模式在客户类当中的调用
    public class Client {public static void main(String[] args) {
            DocumentFactory factory
                = new DocumentFactory();
            Document pdfDocument 
                 = factory.createDocument("pdf");
            pdfDocument.open();
            pdfDocument.save();
            pdfDocument.close();
    
            Document txtDocument 
                  = factory.createDocument("txt");
            txtDocument.open();
            txtDocument.save();
            txtDocument.close();}
    }

    这样简略工厂模式,在不思考将来新文档类型的状况下,的确是一种不错的实现办法。然而在后续的扩大过程当中,如果须要减少新的文档类,就须要去批改 DocumentFactory 中的 createDocument() 办法,减少新的类别,并且客户还必须晓得这些类别能力应用。

    为了应答这种状况,就呈现了工厂办法。工厂办法就间接将工厂形象进去,每个产品对应一个工厂,打消工厂模式中的条件分支构造(其实还有一种打消条件语句的模式,就是之前“组件合作”当中的策略模式)。

    //Document 局部不变
    public interface Document{public void open();
        public void close();
        public void save();
        ......
    }
    public class PdfDocument implements Document{public void open(){//open pdfDocument code}
        // close 和 save
        ......
    }
    public class TxtDocument implements Document{
        //Txt 实现代码
        ......
    }
    // 并且后续能够扩大新的文档类
    ......
    // 批改 factory 局部如下
    public interface DocumentFactory{public Document createDocument();
    }
    public class PdfDocumentFactory 
                implements DocumentFactory {
        @Override
        public Document createDocument() {return new PdfDocument();
        }
    }
    public class TxtDocumentFactory 
                implements DocumentFactory {
        @Override
        public Document createDocument() {return new TxtDocument();
        }
    }
    // 如果后续有新的产品,间接再实现 DocumentFactory, 失去新的工厂
    ......
    // 调用过程可做如下批改:public class Client {public static void main(String[] args) {
            // 利用多态性质,间接生成相应的 factory 子类
            // 打消了管制耦合
            DocumentFactory factory = new PdfDocumentFactory();
            Document pdfDocument
                    = factory.createDocument();
            pdfDocument.open();
            pdfDocument.save();
            pdfDocument.close();
    
            factory = new TxtDocumentFactory();
            Document txtDocument
                    = factory.createDocument();
            txtDocument.open();
            txtDocument.save();
            txtDocument.close();}
    }

    有人可能会有疑难,这样不是还没齐全打消 new 吗?首先这里的客户类曾经到最高的调用档次了,这个过程当中是必然会有 new 的呈现,不然怎么进行程序调用呢?

    咱们所说的打消 new 的过程是指 main 与 factory 之间,产生的一个两头档次(如上面的 App)中去打消 new。

    // 这样的代码中,就打消了 new 的存在
    // 具体的注入过程能够由其余的模式实现,比方 Spring 中的 DI
    public class App{
       private DocumentFactory factory;
        public void setFactory(DocumentFactory factory) {this.factory = factory;}
        public void operateDoc(){Document document = factory.createDocument();
           document.open();
           document.save();
           document.close();}
    }
    //main 中的代码是最高档次,也是变动最频繁的档次,这里是不可能打消 new 的
    public class Client {public static void main(String[] args) {DocumentFactory factory = new PdfDocumentFactory();
            App app = new App();
            app.setFactory(factory);
            app.operateDoc();
            // 同样对于其余的工厂类也是能够采纳同样的形式调用。......
        }
    }

    这样批改代码的益处在那里呢?第一,不言而喻的就是齐全实现了“开闭准则”的思维,扩大时不再须要去批改源码。第二,有些对象的创立过程可能比较复杂,因而如果间接在应用程序当中应用 new 或者其余模式创立很麻烦,通过工厂创立之后,就不再须要去关注那些简单的创立过程。第三,通过 new 创立,始终是一种硬编码的模式,如果在应用程序当中过多的应用这种形式,那么一旦某对象的创立形式产生扭转,批改源码必然是很繁琐的。

  3. 构造——类创立型模式

  4. 参与者

    • Product(Document)

      定义工厂办法中工厂创立的对象的接口。

    • ConcreteProduct(PdfDocument、TxtDocument)

      实现 Product 的接口。

    • Creator(DocumentFactory)

      申明工厂办法——createProduct(),能够调用该办法返回一个 Product 类型的对象。

    • ConcreteCreator(PdfDocumentFactory、TxtDocumentFactory)

      重定义工厂办法以返回具体的 ConcreteProduct。

    • Client(客户类)

      应用工厂和产品,工厂办法模式中,客户类也是一个重要的参与者,因为工厂办法次要的作用就是分来到客户类与产品类之间的耦合关系,所以脱离客户类去谈工厂办法模式时,总会感觉差了些什么货色,无奈齐全领会到工厂办法模式的劣势。

  5. 适用性

    在下列状况下能够应用 Factory Method 模式:

    • 当一个类不晓得它所必须创立的对象的类的时候。
    • 当一个类心愿由它的子类来指定它所创立的对象的时候。
    • 当类将创建对象的职责委托给多个帮忙子类中的某一个,并且你心愿将哪一个帮忙子类是代理者这一信息部分化的时候。

简略地说,就是应用过程中只须要申明一个形象工厂类的援用,具体调用那个工厂去生成那个对象,是由调用者去确定的。

  1. 相干模式

    Abstract Factory 常常用工厂办法来实现,形象工厂创立产品的过程就能够应用工厂办法来实现。

    工厂办法通常在 Template Method 中被调用,这一点在“组件合作”当中也提到过。

  2. 思考

    • Creator 的两种实现状况。第一种状况,Creator 只作为形象层,也就是只申明接口,不做任何的实现;这种状况就必须要子类来实现。第二种状况,Creator 作为一个具体的实现类,而不是抽象类,这种状况下,Creator 能够提供一个缺省的实现接口,这样即便没有子类重写它,客户能够通过这样一个缺省的实现实现工作。
    • 灵活运用工厂办法模式。作为一种创立类模式,在任何须要生成简单对象的中央,都能够应用工厂办法模式。有一点须要留神的中央就是简单对象适宜应用工厂办法模式,而简略对象,特地是只须要通过 new 就能够实现创立的对象(这也是为什么工厂办法解说用到的例子总是无奈压服人的起因之一),无需应用工厂办法模式;因为应用工厂办法模式,就须要引入一个工厂类,会减少零碎的复杂度。

形象工厂(Abstract Factory)

  1. 用意

    提供一个创立一系列相干或相互依赖对象的接口,而无需指定他们具体的类。

  2. 实例

    假设存在这样一个服务层,该层当中须要做的就是拜访数据库中的数据,并且执行一系列的相干操作。依据面向接口编程的思维,能够先作这样一个代码编写。

    // 对数据库进行拜访的三个接口
    // 先建设连贯,再执行相干操作,最初返回相应后果
    public interface DBConnection{}
    public interface DBCommand{}
    public interface DBDataReader{}
    
    // 对于 MySql,能够建设以下实现
    public class MySqlDBConnection implements DBConnection{}
    public class MySqlDBCommand implements DBCommand{}
    public class MySqlDBDataReader implements DBDataReader{}
    // 同样对于 Sql Server,Oricle 也是这样的实现
    ......

    这样的实现下,咱们能够说是满足了面向接口编程的一个思维;并且在实现中,咱们能够为每个接口,依照工厂办法模式,为其创立一个工厂。

    // 工厂接口
    public interface DBConnectionFactory{public DBConnection createDBConnetion();
    }
    public interface DBCommandFactory{public DBCommand createDBCommand();
    }
    public interface DBDataReaderFactory{public DBDataReader createDBDataReader();
    }
    // 而后对于每个具体的数据库,实现不同的具体工厂
    // 以 MySql 为例
    public class MySqlDBConnetionFactory implements DBConnectionFactory {
        @Override
        public DBConnection createDBConnetion() {return new MySqlDBConnection();
        }
    }
    public class MySqlDBCommandFactory implements DBCommandFactory {
        @Override
        public DBDBCommand createDBCommand() {return new MySqlDBCommand();
        }
    }
    public class MySqlDataReaderFactory implements DataReaderFactory {
        @Override
        public DBDataReader createDataReader() {return new MySqlDataReader();
        }
    }
    // 剩下的 Orcle,Sql Server 也是如此
    ......

    工厂模式办法的调用就不再演示,区别和工厂办法中的 Document 例子中差异不大。

    对于这样的实现,尽管咱们很好的利用了工厂办法模式,然而也引入了工厂办法模式的一个弊病——大量的对象和类(本例当中,三个系列,每个系列三个产品,光产品就是 9 个子类;每个产品再对应一个工厂,一共就是 18 个子类)。在应用的过程中,反而可能显著的感觉到零碎复杂度不减反增。并且,DBConnectionDBCommandDBDataReader 显著是有着肯定的关系的,换句话说,MySql 建设的 DBConnection 是和 MySqlDBCommand、MySqlDBDataReader 一起应用的,如果呈现 MySqlDBConnection、OricleDBCommand、SqlServerDBDataReader 这种组合必定是无奈失常执行的。这时形象工厂的呈现,就很好的解决了这样的问题。

    // 首先,具体的产品类不会发生变化,简化的次要是工厂档次
    // 先形象出形象工厂,将产品系列的创立办法合并到一个接口中
    public interface DBFactory{public DBConnection createDBConnetion();
        public DBCommand createDBCommand();
        public DBDataReader createDBDataReader();}
    // 依据不同的具体工厂,创立具体的对象
    public class MySqlDBFactory implements DBFactory {
        @Override
        public DBConnection createDBConnetion() {return new MySqlDBConnection();
        }
    
        @Override
        public DBCommand createDBCommand() {return new MySqlDBCommand();
        }
    
        @Override
        public DBDataReader createDBDataReader() {return new MySqlDBDataReader();
        }
    }
    //Oricle,sql server 的工厂,同样如此
    ......

    形象工厂次要是对工厂档次的简化,这样批改下来,比照工厂办法模式,缩小了 2 / 3 的工厂子类创立,只须要 3 个工厂(有多少个产品系列就有多少个工厂子类)就能够实现产品的创立。

    这样的一种创立工厂形式,不仅缩小了工厂的数量,而且使得产品的一致性得以保障,它能够保障,一次只能应用同一个系列当中的对象。

    public class Client {public static void main(String[] args) {DBFactory factory = new MySqlDBFactory();
            App app = new App();
            app.setFactory(factory);
            app.operate();
            // 同样对于其余的工厂类也是能够采纳同样的形式调用。// ......
        }
    }
    class App{
        private DBFactory factory;
        public void setFactory(DBFactory factory) {this.factory = factory;}
        public void operate(){
            DBConnection connection
                    = factory.createDBConnetion();
            DBCommand command 
                    = factory.createDBCommand();
            DBDataReader reader 
                    = factory.createDBDataReader();
            // 执行相干操作
            .....
        }
    }

    这样的利用程序代码,在肯定水平上就缩小了工厂子类的数量,并且在 operate() 中保障了产品系列的一致性,使得 MysqlDBFactory 生成的产品,只会是与 MySql 相干的。

  3. 构造——对象创立型模式

  4. 参与者

    • AbstractFactory(DBFactory)

      申明一个创立形象产品对象的操作接口。

    • ConcreteFactory(MySqlDBFactory)

      实现创立具体产品对象的操作。

    • AbstractProduct(DBConnection、DBCommand、DBDataReader)

      为一类产品对象申明一个接口。

    • ConcreteProduct(MySqlDBConection、MySqlDBCommand、MySqlDBDataReader)

      定义一个将被相应的具体工厂创立的产品对象,并实现形象产品的相应接口。

    • Client

      调用形象工厂和形象产品提供的接口。在创建者模式当中,客户类也是重要的参加成员,因为对创立模式的了解容易凌乱的点正是在客户类中的调用过程(new)产生的,对于这个问题,曾经在后面做过很多解释了,不再多说。

  5. 适用性

    以下状况能够应用 AbstractFactory 模式:

    • 一个零碎要独立于它的产品的创立、组合和示意时。
    • 一个零碎要由多个产品系列中的一个来配置时。
    • 当你要强调一系列相干的产品对象的设计以便进行联结应用时。
    • 当你提供一个产品类库,而只想显示它们的接口而非实现时。
  6. 相干模式

    Singleton:一个具体的工厂通常会是一个单件。因为在一个利用中,个别每个产品系列只须要一个具体工厂。

    Factory Method:在 Abstract Factory 中,仅仅是申明一个创建对象的接口,真正的创立过程是由具体工厂实现的。这时,能够为每一个办法对应的具体对象之间再定义一个工厂办法。但其问题就在于,这样的做法就像是在工厂办法上再套上一层形象工厂,从而又减少了零碎的复杂度。

  7. 思考

    • 难以反对新品种的产品 对于工厂模式而言,它的最大长处就在于保障了产品的一致性,但也正是如此,这就使得它的产品系列须要保持稳定,如果在后续的过程中呈现新的产品,比方在实例当中须要减少一个新的性能系列,就须要去扩大DBFactory 接口,并且波及到 DBFactory 及其子类的扭转。
    • 定义可扩大的工厂 这是对于新品种产品创立灵活性的进步,然而不太平安;就是给创立 对象的操作减少一个参数,该参数来指定将被创立的对象品种。应用这种形式,形象工厂就只须要一个“Create”办法和一个标识符参数即可实现创立操作。但问题就在于,客户须要齐全理解所有的参数能力更好应用工厂创立本人所须要的对象。

原型模式(Prototype)

  1. 用意

    用原型实例指定对象的创立品种,并且通过拷贝这些原型创立新的对象。

  2. 实例

    Prototype 模式,有点像是对工厂办法模式中产品与工厂的合并。怎么说呢? 看上面的代码:

    // 工厂办法模式中的产品类与工厂办法类
    public interface Document{public void open();
        public void close();
        public void save();
        ......
    }
    public interface DocumentFactory{public Document createDocument();
    }

    这是在 Factory Method 中应用的创立形式,而原型做的事就是,不再用工厂来进行创立,而是转而克隆的形式。变成上面这样:

    // 合并 Document 和 DocumentFactory
    public abstract class Document 
                    implements Cloneable{public void open();
        public void close();
        public void save();
        ......
        // 相当于 Factory 中的 createDocument();
       public Object clone() {
          Object clone = null;
          try {clone = super.clone();
          } catch (CloneNotSupportedException e) {e.printStackTrace();
          }
          return clone;
       }
    }
    public class PdfDocument implements Document{
        @Override
        public void open(){
            //open pdfDocument code
            System.out.println("open pdf!");
        }
        @Override
        public void close() {System.out.println("close pdf!");
        }
        @Override
        public void save() {System.out.println("save pdf!");
        }
        //......
    }
    // 文档类的实现与工厂办法中的一样
    ......

    那么在具体的客户类当中就是通过这样一种形式来进行调用:

    public class App{
        // 在工厂办法模式当中,这里是 documentFactory
        private Document prototype;
        public void setDoucument(Document document){prototype = document;}
        public void useDocument(){//documentFactory.createDocument();
            Document doc = prototype.clone();
            // 而后应用 prototype 克隆进去的 doc 进行操作
            doc.open();
            ......
        }
    }
    // 在客户类中调用体现
    public class Client {public static void main(String[] args) {Document doc = new PdfDocument();
            App app = new App();
            app.setFactory(doc);
            app.useDocument();
            // 同样对于其余的工厂类也是能够采纳同样的形式调用。//......
        }
    }

    问题来了,为什么不间接用原型(prototype),而是要多一步克隆?解决这个问题,首先要明确的是,咱们 应用原型的目标不是将原型作为客户类的一个属性去应用,而是一个创建者。既然是一个创建者,那么在应用的过程中,就不只一个中央会用到同样类型的对象;如果在不同的中央都间接应用原型,可能会在某个中央批改了原型的值,从而使得其余间接应用原型的办法呈现不可预知的谬误。

  3. 构造——对象创立型模式

  4. 参与者

    • Prototype(Document)

      申明一个克隆本身的接口。

    • ConcretePrototype(PdfDocument…)

      继承 Prototype 并实现克隆本身的接口。

    • Client

      让一个原型克隆本身从而创立一个新的对象。

  5. 适用性

    • 当一个零碎应该独立于它的产品创立、形成和示意时,能够应用 Prototype 模式。
    • 当要实例化的类是在运行时候指定时,比方动静装载。
    • 为了防止创立一个产品类平行的工厂类档次时。
    • 当一个类的实例只能有几种不同状态组合中的一种时,建设相应数目的原型并克隆他们能够比每次用适合的状态手工实例化该类更不便一些。
  6. 相干模式

    Abstract Factory 和 Prototype 在某种方面是相互竞争的,然而在某种状况下也是能够一起应用,比方,在形象工厂中存储一个被克隆的产品汇合,在应用时,间接依据汇合中的对象返回相应的产品。

    大量应用 Composite(组合模式)和 Decorator(装璜器模式)的设计上也能够采纳 Protorype 来缩小 Composite 或 Decorator 对象的创立。

  7. 思考

    • 缩小了子类的结构。实例当中就能够看出,原型模式简化了工厂办法模式中的工厂类,因而,缩小了许多子类的创立。
    • 资源优化。类初始化可能须要消化十分多的资源,这个资源包含数据、硬件资源等等,应用原型模式就能够缩小这样一个初始化过程。
    • 深、浅拷贝的问题。对于 java 而言,浅拷贝实现 Cloneable,深拷贝是通过实现 Serializable 读取二进制流。

建造者模式(Builder)

  1. 用意

    将一个简单对象的构建与它的示意拆散,使得同样的构建过程能够有不同的示意。

  2. 实例

    在游戏场景当中,尤其是 3d 场景中,必不可少就是建筑物,比如说房子。对房子的构建必定不是一下全部构建实现的,而是会分成几个局部,比方墙、窗户、地板、房顶、门,一部分、一部分地去构建。

    public abstract class House{
        // 房子属性,纹理、材质...
        private Texture texture;
        private Material material;
        ......
        // 墙、窗户、地板、房顶、门
        public Wall buildWall();
        public Window buildWindow();
        public Floor buildFloor();
        public Door buildDoor();
        public Roof buildRoof();
        // 房子构建过程
        public void buildHouse(){buildFloor();
            Wall[] walls = new Wall[4];
            for(int i=0;i<walls.length;i++)
                walls[i] = buildWall();
            Window window = buildWindow();
            wall[1].setWindow(window);
            Door door = builDoor();
            wall[2].setDoor(door);
            buildRoof();}
    }

    这种构建形式,采纳的显著就是模板办法(Template Method),这种实现形式还能够依据不同的房子类型,实现具体的细节。

    // 石头屋
    public class StoneHouse extends House{
        // 具体实现细节
        .......
    }
    // 茅草屋
    public class ThatchedHouse extends House{
        // 具体实现细节
        .......
    }
    // 依照模板主办法在客户类中的调用模式体现:public class Client{public static void main(String[] args){
            // 只须要生成一个相应对象即可在游戏场景中实现相应类型房子的创立
            House house = new StoneHouse();
            house.buildHouse();    // 生成石头屋
            
            house = new ThatchedHouse();
            house.buildHouse();    // 生成茅草屋}
    }

    这种实现有什么问题呢?类太臃肿了,对吧~ 这样的实现过程,能够体现复用的思维,然而问题之一就在于所有的内容全副都放在了一个类中,体现不出繁多职责和类的信息与行为集中;这时就能够将创立过程分离出来,造成一个 Builder,由这样一个 Builder 来专门负责创立。

    //Director
    public class House{
        // 房子属性,纹理、材质...
        private Texture texture;
        private Material material;
        ......
        // 减少 builder 的引入
        private HouseBuilder houseBuilder;
        public void setHouseBuilder(HouseBuilder hBuilder){houseBuilder = hbuilder;}
        // 房子构建过程
        public void buildHouse(){houseBuilder.buildFloor();
            Wall[] walls = new Wall[4];
            for(int i=0;i<walls.length;i++)
                walls[i] = houseBuilder.buildWall();
            Window window 
                = houseBuilder.buildWindow();
            wall[1].setWindow(window);
            Door door = houseBuilder.builDoor();
            wall[2].setDoor(door);
            houseBuilder.buildRoof();}
    }
    
    // 分离出来的 builder
    public interface HouseBuilder{
        // 墙、窗户、地板、房顶、门
        public Wall buildWall();
        public Window buildWindow();
        public Floor buildFloor();
        public Door buildDoor();
        public Roof buildRoof();}
    public class StoneHouseBuilder
                    implements HouseBuilder{
        // 具体实现细节
        .......
    }
    public class ThatchedHouseBuilder 
                    implements HouseBuilder{
        // 具体实现细节
        .......
    }
    // 批改过后,在客户类中的调用模式体现:public class Client{public static void main(String[] args){
            // 只须要生成一个相应对象即可在游戏场景中实现相应类型房子的创立
            House house = new House();
            HouseBuilder builder 
                    = new StoneHouseBuilder();
            house.setHouseBuilder(builder);
            house.buildHouse();
            
            builder = new ThatchedHouseBuilder();
            // 这个 set 过程能够运行时实现
            house.setHouseBuilder(builder);
            house.buildHouse();}
    }

    通过这样一种形式,实现简单对象构建与示意的拆散,并且,对于不同的房子对象,如果房子其余参数没有任何差异,就只须要传入相应的 builder 即可,而不须要再生成各种各样的子类(如StoneHouse、ThatchedHouse)。

    一旦生成对象,只须要批改其 builder 就能够马上扭转其对象示意,而不须要新生成对象。并且这种批改过程,是能够动静实现的,就如果 Spring 当中的依赖注入过程一样,能够在运行时刻实现,而不肯定是一开始就确定的

  3. 构造——对象创立型模式

  4. 参与者

    • Builder(HouseBuilder)

      为创立一个 Product 对象的各个部件指定形象接口。

    • ConcreteBuilder(StoneHouseBuilder、ThatchedHouseBuilder)

      • 实现 Builder 的接口以结构各拆卸该产品的各个部件。
      • 定义并明确它所创立的示意。
    • Director(House)

      结构一个应用 builder 的对象。

    • Product(Wall、Window…)

      蕴含了定义组成部件的类以及被结构的简单对象等。

  5. 适用性

    Builder 的实用状况:

    • 当创立简单对象的算法应该独立于该对象的组成部分,以及它们的拆卸形式时。
    • 当结构过程必须容许被结构的对象的不同的示意时。

Builder 模式更多的是体现的一种思维,而不是具体的过程,这种思维就是,当一个类的信息与行为过于臃肿时,兴许能够采纳 Builder 这种形式对类的信息与行为进行从新划分,从而使得类看起来更加的“轻”。

  1. 相干模式

    Abstract Factory 和 Builder 都是对简单对象的创立封装,但二者的区别在于,Builder 着重于一步一步构建一个简单对象,而 Abstract Factory 着重于多个系列产品对象的创立,并且系列对象之间有着某种分割。

    Composite 模式中对象通常状况下就是用 Builder 生成的。

  2. 思考

    • 能够扭转产品的外部示意 Builder 对象提供给 Director 一个结构产品对象的外部接口,从而使得产品的示意和内部结构得以暗藏。因而,在构建过程中,只须要替换不同的 Builder 就能够失去不同的示意。
    • Builder 中的办法能够缺省为空 这样在具体的实现过程中,客户能够只实现他们感兴趣的操作,这种形式其实在很多模式中都能够利用,其最次要的思维就是能用默认配置当然是最好的。

最初,最近很多小伙伴找我要Linux 学习路线图,于是我依据本人的教训,利用业余时间熬夜肝了一个月,整顿了一份电子书。无论你是面试还是自我晋升,置信都会对你有帮忙!

收费送给大家,只求大家金指给我点个赞!

电子书 | Linux 开发学习路线图

也心愿有小伙伴能退出我,把这份电子书做得更完满!

有播种?心愿老铁们来个三连击,给更多的人看到这篇文章

举荐浏览:

  • 干货 | 程序员进阶架构师必备资源免费送
  • 神器 | 反对搜寻的资源网站

正文完
 0