《(1.9)--第5.4章-工厂模式软件设计与体系结构.ppt》由会员分享,可在线阅读,更多相关《(1.9)--第5.4章-工厂模式软件设计与体系结构.ppt(53页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第5.4章 工厂模式1New操作制造对象的方法实例化一个具体类针对实现,而非针对接口使用New操作,是在针对实现编程除了New操作符之外,还有哪些制造对象的方法?第5.4章 工厂模式2在运行时根据条件来实例化具体的类一旦有变化或扩展,就必须对这段代码进行修改目标:如何将实例化具体类的代码从应用中抽离、或者封装起来,使它们不会干扰应用的其他部分?实例:比萨店业务模拟系统比萨:制造的对象第5.4章 工厂模式3第5.4章 工厂模式4更多的比萨类型第5.4章 工厂模式5增加更多的比萨类型,淘汰不畅销的比萨类型?第5.4章 工厂模式6找到并分离变化的部分工厂(factory)处理创建对象的细节order
2、Pizza成为该对象的客户,即需要一个对象时,就叫工厂做一个orderPizza只关心得到了一个对象,只要它实现了Pizza接口第5.4章 工厂模式7建立一个简单的比萨工厂第5.4章 工厂模式8问题这么做似乎只是把问题搬到另一个对象中罢了,问题依然存在?SimplePizzaFactorySimplePizzaFactory可以有许多客户。虽然目前只有可以有许多客户。虽然目前只有orderPizzaorderPizza()()方法是它的客户,然后可能还有其他类方法是它的客户,然后可能还有其他类(HomeDelivery)(HomeDelivery)会利用这个工厂来取得比萨。因此,会利用这个工厂
3、来取得比萨。因此,把创建比萨的代码包装进一个类,当以后实现改变时,把创建比萨的代码包装进一个类,当以后实现改变时,只需修改这个类即可。只需修改这个类即可。这种简单工厂还有其他的设计方式吗?可以使用静态方法定义一个简单的工厂,也称之为静可以使用静态方法定义一个简单的工厂,也称之为静态工厂。态工厂。publicstaticPizzacreatePizza(Stringname)第5.4章 工厂模式9重做PizzaStore类10简单工厂(更多的像是一种编程习惯,而非设计模式)简单工厂(更多的像是一种编程习惯,而非设计模式)第5.4章 工厂模式11简单工厂的引申比萨店加盟NYPizzaFactory
4、ChicagoPizzaFactory第5.4章 工厂模式12简单工厂的引申比萨店加盟第5.4章 工厂模式13利用SimplePizzaFactory,写出多个不同的工厂(NYPizzaFactory、ChicagoPizzaFactory、),各地加盟店都有适合的工厂可以使用目标:引入更多质量控制(捆绑PizzaStore和PizzaFactory)第5.4章 工厂模式14一种新的比萨店框架:工厂方法模式第5.4章 工厂模式15让createPizza()应对加盟店之间的差异,并负责创建正确种类的比萨第5.4章 工厂模式16orderPizza()方法在抽象的PizzaStore内而不是在子
5、类内定义,因此此方法并不知道哪个子类将实际上制作比萨orderPizza()方法对Pizza对象做了很多事情,但是由于Pizza对象是抽象的,orderPizza()并不知道哪些实际的类参与进它的操作当orderPizza()调用createPizza()时,某个比萨加盟店(NYStylePizzaStore、ChicagoStylePizzaStore)负责创建比萨第5.4章 工厂模式17加盟店只需继承PizzaStore类,然后提供createPizza()方法实现自己的比萨风味第5.4章 工厂模式18问题:实现另外一个比萨加盟店第5.4章 工厂模式19第5.4章 工厂模式20工厂方法用来
6、处理对象的创建,并将这样的行为封装在子类中。这样可以客户程序中关于超类的代码和子类对象创建代码解耦合。解耦合:orderPizza()并不知道参与的比萨类型第5.4章 工厂模式21使用比萨工厂方法订购比萨Ethan和Joel需要取得比萨店的实例有了各自的PizzaStore,Ethan和Joel分别调用orderPizza()方法,传入他们喜爱的比萨类型orderPizza()调用createPizza()创建比萨,但是它并不知道真正创建的是哪一种比萨,只知道这个比萨能够被烘烤、切片、装盒orderPizza()提供比萨给Ethan和JoelEthanEthan:New New York Ch
7、eese York Cheese PizzaPizzaJoelJoel:Chicago Chicago Cheese PizzaCheese Pizza227.4 工厂模式1.先需要一个纽约比萨店2.在纽约比萨店内下订单3.orderPizza()方法调用createPizza()方法4.每个比萨都必须经过如下处理才算完成orderPizza()23实实现现比比萨萨抽抽象象类类24实现比萨具体子类实现比萨具体子类第5.4章 工厂模式25测试比萨店业务模拟系统第5.4章 工厂模式26测试比萨店业务模拟系统第5.4章 工厂模式27工厂方法模式(Factory Method Pattern)创建者类
8、(Creator)第5.4章 工厂模式28工厂方法模式(Factory Method Pattern)产品类(Product)29平行的类层次平行的类层次第5.4章 工厂模式30定义工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。用途工厂模式用于封装对象的创建特点工厂模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。决定:并不是指模式允许子类本身在运行时做决定,而是指在编写创建者类时,不需要知道实际创建的产品是哪一个。第5.4章 工厂模式31工厂方法模式框架第5.4章 工厂模式32问题当只有一个Concrete Cr
9、eator时,工厂模式还有优点吗?尽管只有一个具体的创建者,工厂模式依然很有用,因为它尽管只有一个具体的创建者,工厂模式依然很有用,因为它使得我们将产品的使得我们将产品的“实现实现”从从“使用使用”中解耦;如果增加产中解耦;如果增加产品或者改变产品的实现,品或者改变产品的实现,CreatorCreator并不受影响。并不受影响。工厂方法和创建者是否总是抽象的?不一定,可以定义一个默认的工厂方法来产生某些具体的产不一定,可以定义一个默认的工厂方法来产生某些具体的产品,这样即使创建者没有任何子类,依然可以创建产品。品,这样即使创建者没有任何子类,依然可以创建产品。在利用字符串传入参数化的类型,如果
10、把参数“Clam”英文拼错成“Calm”,要求供应“CalmPizza”,应该如何处理?这种情形会造成运行时错误,有一些技巧可以避免这个错误,这种情形会造成运行时错误,有一些技巧可以避免这个错误,使得在编译时就将参数上的错误挑出来,比如:使得在编译时就将参数上的错误挑出来,比如:创建代表参数类型的对象、使用静态常量、创建代表参数类型的对象、使用静态常量、enumenum数据类型等数据类型等等。等。第5.4章 工厂模式33问题简单工厂和工厂方法之间的差异在哪?简单工厂把全部的事情,在一个地方处理完了;而工简单工厂把全部的事情,在一个地方处理完了;而工厂方法却是创建一个框架,让子类决定要如何实现。
11、厂方法却是创建一个框架,让子类决定要如何实现。在工厂方法中,在工厂方法中,orderPizza()orderPizza()方法提供了一般的框架,方法提供了一般的框架,以便创建比萨,以便创建比萨,orderPizza()orderPizza()方法依赖工厂方法创建方法依赖工厂方法创建具体类,并制造出实际的比萨;另外可通过继承具体类,并制造出实际的比萨;另外可通过继承PizzaStorePizzaStore类,决定实际制造出的比萨是什么。类,决定实际制造出的比萨是什么。简单工厂的做法,可以将对象的创建封装起来,但是简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单
12、工厂不能简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。变更正在创建的产品。34如如果果不不使使用用OOOO工工厂厂的的代代码码由比萨店创建所有的比萨对象,而不是委托给工厂35对对象象依依赖赖图图虽然创建了抽象的Pizza类,但是仍然在代码中实际地创建了具体的Pizza,所以这个抽象没有什么影响力36对象依赖图对象依赖图(使用工厂方法(使用工厂方法之后)之后)第5.4章 工厂模式37依赖倒置原则(Dependency Inversion Principle)要依赖抽象类,不要依赖具体类不能让高层组件依赖底层组件,而且不管高层或底层组件,两者都应该依赖于抽象高层组件是由其它底层
13、组件定义其行为的类PizzaStore是高层组件,因为它的行为是由Pizza定义的:PizzaStore创建并处理所有不同的Pizza对象,而Pizza属于顶层组件第5.4章 工厂模式38如何避免违反依赖倒置原则变量不可以持有具体类的引用如果使用new,就会持有具体类的引用,我们可以改用工厂来避开这样的做法不要让类派生自具体类如果派生自具体类,我们就会依赖具体类;最好派生自一个抽象类或接口不要覆盖基类中已经实现的方法如果覆盖基类已实现的方法,那么基类就不是一个真正适合被继承的抽象。基类中以实现的方法,应该有所有的子类共享尽量而不是随时遵守这个原则第5.4章 工厂模式39考虑比萨的原材料更复杂的
14、工厂模式第7章 设计模式40所有比萨都是使用相同的组件制造而成,但是每个区域对于这些组件却有不同的实现每个区域都包含了一种面团(Dough)、一种酱料(Sauce)、一种芝士(Cheese),以及一种海鲜佐料(Clam)整体来说,这两个区域组成了原料家族,每个区域实现了一个完整的原料家族7.4 工厂模式第5.4章 工厂模式41为每个区域建造一个原料工厂实现一组原料类供工厂使用,这些类可以在合适的区域内共享把新的原料工厂整合进旧的PizzaStore代码中原料工厂接口原料工厂接口第7章 设计模式427.4 工厂模式纽约原料工厂纽约原料工厂第7章 设计模式43PizzaPizza抽象类抽象类第5.
15、4章 工厂模式44基于抽象Pizza类创建不同区域的具体比萨让原料工厂处理比萨之间的区域差异Pizza的代码利用相关的工厂生产原料,所生产的原料依赖于所使用的工厂,Pizza类并不关系这些原料第7章 设计模式457.4 工厂模式第5.4章 工厂模式46引入了新类型的工厂(抽象工厂),来创建比萨原料家族(Dough、Sauce、Cheese、)PizzaIngredientFactory从抽象工厂中派生出一些具体工厂,这些工厂产生相同的产品(通过抽象工厂所提供的接口可以创建产品的家族),但是产品的实现不同NYPizzaIngredientFactoryCheesePizza客户程序使用这个工厂来
16、创建产品,通过传入不同的工厂,可以制造出各种不同的产品NYPizzaStore第5.4章 工厂模式47重新订购比萨1.先需要一个纽约比萨店2.在纽约比萨店内下订单EthanEthan:New New York Cheese York Cheese PizzaPizzaJoelJoel:Chicago Chicago Cheese PizzaCheese Pizza第5.4章 工厂模式48重新订购比萨3.orderPizza()方法调用createPizza()方法4.createPizza()方法被调用时,开始涉及原料工厂5.调用prepare()准备原料6.bake、cut、box第5.4章
17、 工厂模式49抽象工厂模式定义提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要关心实际产生出的具体产品是什么抽象工厂的任务是定义一个负责创建一组产品的接口,这个接口内的每个方法都负责创建一个具体产品,同时我们利用实现抽象工厂的子类来提供这些具体的做法抽象工厂利用工厂方法实现产品的生产第5.4章 设计模式50抽象工厂模式类图抽象工厂模式类图Client第5.4章 抽象抽象工厂模式51实例女娲造人第5.4章 工厂模式52简单工厂优点:职责明确缺点:工厂类集中了所有实例的创建逻辑工厂方法 优点:解耦框架;多态性缺点:需要客户及子类作为工厂方法的载体抽象工厂优点:产品族保护;扩展性(增加新的具体工厂、产品族)缺点:复杂第5.4章 工厂模式53小结所有的工厂都用来封装对象的创建简单工厂方法把对象创建过程进行封装工厂方法使用继承,把对象的创建委托给子类,子类通过实现工厂方法来创建对象抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合工厂方法允许将实例化延迟到子类进行抽象工厂创建相关的对象家族,而不需要依赖它们具体类
限制150内