《设计模式02》-工厂方法
- 格式:ppt
- 大小:701.50 KB
- 文档页数:24
设计模式工厂方法工厂方法(Factory Method)是一种创建型设计模式,它通过定义一个独立的工厂接口来创建对象,具体的对象创建由具体的工厂类负责。
工厂方法模式有以下几个角色:1. 抽象产品(Product):定义了产品的接口,是具体产品的父类。
2. 具体产品(ConcreteProduct):实现了抽象产品接口。
3. 抽象工厂(Factory):定义了工厂的接口,提供了创建产品的方法。
4. 具体工厂(ConcreteFactory):实现了抽象工厂接口,负责实际创建具体产品对象。
工厂方法模式的优点包括:1. 解耦了具体产品的创建和使用,客户端只需要关注抽象产品和抽象工厂接口。
2. 符合开闭原则,易于扩展新的产品和工厂。
3. 可以通过配置文件等方式来动态创建具体工厂类。
工厂方法模式的适用场景包括:1. 客户端不知道具体产品的类名,只知道抽象产品的接口。
2. 一个系统需要支持多种具体产品的创建。
3. 客户端和具体产品的解耦是必要的,避免客户端直接依赖具体产品。
举个例子,假如我们要实现一个简单的形状(Shape)工厂,可以生产圆形和正方形。
首先定义抽象产品接口Shape,具有一个绘制方法draw。
然后定义具体产品类Circle和Square,实现抽象产品接口。
接下来定义抽象工厂接口ShapeFactory,提供一个创建Shape对象的方法createShape。
最后实现具体工厂类CircleFactory和SquareFactory,分别负责创建具体产品类Circle和Square对象。
使用工厂方法模式,客户端只需要通过创建具体工厂对象,调用createShape 方法来创建具体产品,而无需知道具体产品的类名。
抽象产品接口interface Shape {void draw();}具体产品类:圆形class Circle implements Shape {public void draw() {System.out.println("画一个圆形");}}具体产品类:正方形class Square implements Shape {public void draw() {System.out.println("画一个正方形");}}抽象工厂接口interface ShapeFactory {Shape createShape();}具体工厂类:圆形工厂class CircleFactory implements ShapeFactory { public Shape createShape() {return new Circle();}}具体工厂类:正方形工厂class SquareFactory implements ShapeFactory { public Shape createShape() {return new Square();}}客户端public class Client {public static void main(String[] args) {ShapeFactory factory = new CircleFactory();Shape shape = factory.createShape();shape.draw();}运行结果:画一个圆形。
Java设计模式-⼯⼚⽅法模式⼯⼚⽅法模式(Factory Method Pattern),是简单⼯⼚模式的扩展,定义⼀个创建对象的接⼝,但是让⼦类来觉得该实例化那个类。
⼯⼚⽅法让⼀个类推迟实例化⾄它的⼦类中。
⼯⼚⽅法模式有四个⾓⾊:抽象⼯⼚(Creator)⾓⾊:这是⼯⼚⽅法模式的核⼼,具体⼯⼚⾓⾊必须实现这个接⼝才能创建对象。
具体⼯⼚(Concrete Creator)⾓⾊:实现了抽象⼯⼚⾓⾊的接⼝,实现了抽象⼯⼚,⽤具具体产品的创建。
抽象产品(Product)⾓⾊:定义了产品的共性,实现对产品最抽象的定义。
具体产品(Concrete Product)⾓⾊:实现抽象产品⾓⾊的接⼝。
⼯⼚⽅法所创建的对象就是该⾓⾊的实例。
⼯⼚⽅法模其类图如下:抽象⼯⼚的代码模式:public abstract class AbstractComputerFactory {/*** 创建计算机抽象⽅法** @param tClass* @param <T> 泛型类* @return*/public abstract <T extends AbstractComputer> T createComputer(Class<T> tClass);}抽象产品的代码模式:/*** 抽象计算机类*/public abstract class AbstractComputer {/*** 抽象⽅法** @param info*/public abstract void printInfo(String info);}具体⼯⼚的代码模式:@Componentpublic class ComputerFactory extends AbstractComputerFactory {/*** 创建计算机抽象⽅法** @param tClass* @param <T> 泛型类* @return*/public <T extends AbstractComputer> T createComputer(Class<T> tClass) {AbstractComputer computer = null;try {computer = (AbstractComputer) tClass.getDeclaredConstructor().newInstance();} catch (Exception e) {e.printStackTrace();}return (T) computer;}}具体产品的代码模式:此处⽣产两种不同的产品,Apple和ThinkPad/*** 苹果笔记本*/@Componentpublic class AppleComputer extends AbstractComputer {/*** 输出** @param info*/public void printInfo(String info) {System.out.println(info);}}/*** ThinkPad 笔记本*/@Componentpublic class ThinkPadComputer extends AbstractComputer {/*** 输出** @param info*/public void printInfo(String info) {System.out.println(info);}}测试:@SpringBootTestclass AbstractComputerFactoryTest {@Autowiredprivate AbstractComputerFactory computerFactory;@Testvoid showComputerInfo() {AbstractComputer thinkPadComputer = computerFactory.createComputer(ThinkPadComputer.class);AbstractComputer appleComputer = computerFactory.createComputer(AppleComputer.class);thinkPadComputer.printInfo("这是 ThinkPad 笔记本。
工厂方法模式工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种将对象的实例化过程委托给子类的方式。
工厂方法模式将对象的创建与使用分离,客户端通过调用工厂类的方法来创建对象,而不直接调用对象的构造方法。
这样做的好处是,客户端不需要知道具体的对象是如何创建的,只需要知道如何使用即可,从而实现了对对象创建过程的封装。
在工厂方法模式中,通常会定义一个抽象的工厂类,其中包含一个抽象的工厂方法,用于创建产品对象。
具体的产品类通过继承工厂类,并实现工厂方法来创建具体的产品对象。
以生产手机的工厂为例,工厂类可以定义一个抽象的手机工厂类,其中包含一个抽象的生产手机的方法。
具体的手机品牌如苹果、小米、华为等可以通过继承工厂类,并实现生产手机的方法来创建具体的手机对象。
工厂方法模式的优点有:1. 降低了代码的耦合性。
客户端只需要依赖抽象的工厂接口即可,不需要依赖具体的产品类。
2. 提供了可扩展性。
通过定义抽象的工厂类和具体的工厂子类,可以方便地新增产品对象,而不需要修改现有的代码。
3. 符合开闭原则。
对于新增产品对象,只需要新增具体的工厂子类即可,不需要修改其他代码。
工厂方法模式的缺点有:1. 增加了系统的复杂度。
引入了抽象的工厂类和具体的工厂子类,增加了系统的结构和复杂度。
2. 增加了代码的数量。
相比直接调用对象的构造方法,通过工厂方法模式创建对象的方式需要更多的代码。
工厂方法模式在实际的开发中应用广泛。
例如,在数据库访问层中,往往会定义一个抽象的数据库工厂接口,其中包含抽象的数据库连接方法,具体的数据库厂商如MySQL、Oracle等可以通过实现数据库工厂接口来创建具体的数据库连接对象。
这样做的好处是,可以方便地切换不同的数据库,而不需要修改现有的代码。
总之,工厂方法模式是一种非常实用的设计模式,它将对象的创建过程委托给子类,降低了代码的耦合性,提高了系统的可扩展性和可维护性。
设计模式:工厂方法模式今天说一下工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。
工厂方法让类把实例化推迟到子类所谓的决定并不是批模式允许子类本身在运行时做决定,而是指在编写创建者类时,不需知道创建的产品是哪一下,选择了使用哪个子类,就决定了实际创建的产品是什么。
1#region工厂模式23// 产品4public abstract class Product5{6public string productName;7}89// 建造者10//工厂方法是创建一个框架,让子类决定要如何实现具体的产品11public abstract class Creator12{13public Product FactoryMethod(string f_ProductType)14{15Product _product;16_product=CreateProduct(f_ProductType);//可对产品做其它的操作......17return_product;18}19//让子类去实现要生产什么产品20public abstract Product CreateProduct(string f_Type);2122}23#region产品24public class OneProduct : Product25{26public OneProduct()27{28productName = "OneProduct";29}30}3132public class TwoProduct : Product33{34public TwoProduct()35{36productName = "TwoProduct";37}38}3940public class FirstProduct : Product41{42public FirstProduct()43{44productName = "My FirstProduct";45}46}4748public class SecondProduct : Product49{50public SecondProduct()51{52productName = "My SecondProduct";53}54}55#endregion56//第一个建造工厂57public class OneCreator : Creator58{59public override Product CreateProduct(string f_Type) 60{61switch(f_Type)62{63case"one":64return new OneProduct();65case"two":66return new TwoProduct();67}6869return null;70}71}72//第二个建造工厂73public class TwoCreator : Creator74{75public override Product CreateProduct(string f_Type) 76{77switch(f_Type)78{79case"one":80return new FirstProduct();81case"two":82return new SecondProduct();83}84return null;85}86}87888990#endregion1static void Main(string[] args)2{345#region工场模式6789//第一个工厂两种产品10Creator _creator = new OneCreator();11Product _product = _creator.FactoryMethod("one");12Console.WriteLine(_product.productName);13_product = _creator.FactoryMethod("two");14Console.WriteLine(_product.productName);1516//第二个工厂造另两种产品1718Creator _tCreator = new TwoCreator();19Product _tProduct = _tCreator.FactoryMethod("one");20Console.WriteLine(_tProduct.productName);21_tProduct = _tCreator.FactoryMethod("two");22Console.WriteLine(_tProduct.productName);23#endregion2425Console.ReadLine();26}让我们来看一下依赖关系我们会看到 Creator 和所有的产品(OneProduct、TwoProduct...)都依赖了Product.这是依赖倒置原则:要依赖抽象,不要依赖具体类也就是说不能让具体产品去依赖Creator,不管是产品还是Creator都应该依赖于抽象就用这个原则我们要尽量做到1变量不可以持有具体类的引用(如果使用new就会有具体类的引用。
设计模式之⼯⼚模式(3种)详解及代码⽰例 ⼯⼚模式划分来说总共有三类:简单⼯⼚模式、⼯⼚⽅法模式和抽象⼯⼚模式。
其中简单⼯⼚模式不输⼊23种设计模式之⼀,但他们⼜都属于创建型模式。
我们依次讲解这三种⼯⼚模式。
⼀、简单⼯⼚ 1、什么是简单⼯⼚模式? ⾸先来说简单⼯⼚,简单⼯⼚模式,⼜叫做静态⼯⼚模式(Static Factory Method),由⼀个⼯⼚对象决定创建出哪⼀种产品类的实例,简单⼯⼚模式的实质是由⼀个⼯⼚类根据传⼊的参数,动态决定应该创建哪⼀个产品类。
属于创建型模式,但不属于GOF23设计模式。
2、简单⼯⼚适⽤场景 ⼯⼚类负责创建的对象⽐较少;客户端(应⽤层)只需要知道传⼊⼯⼚类的参数,对于如何创建对象(逻辑)不关⼼。
3、简单⼯⼚优缺点优点:只需要传⼊⼀个正确的参数,就可以获取你所需要的对象,⽽⽆需知道其细节创建。
缺点:⼯⼚类的职责相对过重,增加新的产品,需要修改⼯⼚类的判断逻辑,违背了开闭原则。
4、简单⼯⼚实现 ⾸先来看类图: 代码实现:public class ShapeFactory {public Shape getShape(String shapeType){if(shapeType.equalsIgnoreCase("circle")){return new Circle();}else if(shapeType.equalsIgnoreCase("rectangle")){return new Rectangle();}else if(shapeType.equalsIgnoreCase("squere")){return new Squere();}return null;}public Shape getShape(Class clazz) throws Exception{return (Shape) clazz.newInstance();}}⼆、⼯⼚⽅法模式 1、什么是⼯⼚⽅法 ⼯⼚⽅法模式(Factory Method),⼜称多态性⼯⼚模式,属于设计模式三⼤分类中的创建型模式,作为抽象⼯⼚模式的孪⽣兄弟,⼯⼚⽅法模式定义了⼀个创建对象的接⼝,但由⼦类决定要实例化的类是哪⼀个,也就是说⼯⼚模式让实例化推迟到⼦类。
当看到"new",就会想到"具体","new"有什么不对劲的?在技术上,new没有错,毕竟这是java的基础部分.针对接口编程,可以隔离掉以后系统可能发生的一大堆改变.为什么呢?如果代码是针对接口而写,你们通过多态,它可以与任何新类实现该接口.但是,当代码使用大量的具体类时,等于是自找麻烦,因为一但加入新的具体类就必须改变代码,也就是说你的代码并非"对修改关闭".别忘了,我们的第一个原则用来处理改变,"找出会变化的方面,把它们从不变的部分分离出来".假设你有个披萨店,你的代码可能这么写:Java代码pizza orderPizza(){Pizza piz = new Pizza();//为了让系统有弹性,我们很希望这是一个抽象类或接口,但如果这样,这些类或接口就无法直接实例化piz.prepare();piz.bake();piz.cut();piz.box();return piz;}但是你需要更多的披萨类型,所以必须增加一些代码,来决定适合的披萨类型,然后再制造这个披萨:Java代码pizza orderPizza(String type){//现在把披萨类型传入orderPizzaPizza piz;//根据披萨的类型,实例化正确的具体类,注意这里的任何披萨都必须实现Pizza接口if(type.equals("cheese")){piz = new CheesePizza();}else if(type.equals("greek")){piz = new GreekPizza();}//某一天你为了赶上竞争者,你加入了一些流行风味的披萨,greek披萨卖的不好,你要从菜单去掉,随着时间的过去,这里就必须一改再改else if(type.equals("clam")){piz = new ClamPizza();}else if(type.equals("veggie")){piz = new VeggaePizza();}//一旦我们有了一个披萨,需要做一些准备,然后烘烤.切片.装盒,这里是我们不想改变的地方piz.prepare();piz.bake();piz.cut();piz.box();return piz;}现在我们知道哪些会改变哪些不会改变,该是使用封装的时候了,现在我们把创建对象的代码抽离,建立一个简单披萨工厂,这个工厂只管如何创建披萨:Java代码public class SimplePizzaFactory {//内定一个createPizza()方法,所有客户通过这个方法来实例化新对象public Pizza createPizza(String type) {Pizza pizza = null;//移植过来的代码,基本没什么变动if (type.equals("cheese")) {pizza = new CheesePizza();} else if (type.equals("pepperoni")) {pizza = new PepperoniPizza();} else if (type.equals("clam")) {pizza = new ClamPizza();} else if (type.equals("veggie")) {pizza = new VeggiePizza();}return pizza;}}这么做有什么好处?似乎只是把问题搬到另一个对象罢了,问题依然存在.别忘了,SimplePizzaFactory可以有很多客户,虽然目前只看到orderPizza()方法是它的客户,然而可能还有其他的客户.所以把创建披萨的代码包装进一个类,当以后实现改变时,只需修改这个类即可.别忘了,我们正要把具体实例化过程从客户的代码中删除.修改客户代码,重做PizzaStore类:Java代码public class PizzaStore {//加一个SimplePizzaFactory的引用SimplePizzaFactory factory;public PizzaStore(SimplePizzaFactory factory) {this.factory = factory;}public Pizza orderPizza(String type) {Pizza pizza;//而orderPizza()方法通过简单传入订单类型来使用工厂创建披萨,//请注意,我们把new操作符替换成工厂对象的创建方法,这里不在使用具体实例化pizza = factory.createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}//...other methon}简单工厂其实不是一个设计模式,反而比较像是一种编程习惯,接下来继续用披萨店来讲述工厂方法模式.披萨店经营有成,击败了竞争者,现在大家都希望来加盟你的披萨店,身为经营者,你希望确保加盟店的营运质量,希望这些店都使用你那些经过时间考验的代码.但是区域的差异呢?每家加盟店都可能想要提供不同风味的披萨,比方说纽约.芝加哥.加州,这就受到了开店地点及该地区口味的影响.如果利用SimplePizzaFactory,写出3种不同的工厂,分别是NYPizzaFactory,ChicagoPizzaFactory,CaliforniaPizzaFactory,那么各个加盟店都有合适的工厂可以使用,这是一种做法:NYPizzaFactory nyFactory = new NYPizzaFactory();//这里创建的工厂是制造纽约风味的披萨PizzaStore nyStore = new PizzaStore(nyFactory);//然后建立一个披萨店,将纽约工厂的引用作为参数nyStore.orderPizza("Veggie"); //制造披萨,会得到纽约风味的披萨在推广SimplePizzaFactory时,你发现加盟店的确采用你的工厂创建披萨,但是他们自创流程:烘烤的做法有些差异.不要切片.使用其他厂商的盒子.怎么让你的质量多一些质量控制多些弹性呢?我们再来修改一些披萨店,先声明一个工厂方法:Java代码//现在PizzaStore是抽象的,每个子类都会覆盖createPizza方法,同时使用PizzaStore定义的orderPizza方法,//甚至可以把orderPizza定义为tinal,以防止被之类覆盖public abstract class PizzaStore {/***现在把工厂对象移到这个方法中,工厂方法现在是抽象的,所以依赖子类来处理对象的创建*工厂方法必须返回一个产品,超类中定义的方法,通常使用到工厂方法的返回值 *工厂方法将客户(如orderPizza)和实际创建具体产品的代码分割开来*/abstract Pizza createPizza(String type);public Pizza orderPizza(String type) {//现在createPizza()方法从工厂对象中移回PizzaStorePizza pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}}好了,让我们把纽约风味的加盟店开起来吧:Java代码//createPizza()返回一个Pizza对象,由子类全权负责该实例化哪一个具体Pizza public class NYPizzaStore extends PizzaStore {//必须实现的createPizza方法Pizza createPizza(String item) {if (item.equals("cheese")) {return new NYStyleCheesePizza();} else if (item.equals("veggie")) {return new NYStyleVeggiePizza();} else if (item.equals("clam")) {return new NYStyleClamPizza();} else if (item.equals("pepperoni")) {return new NYStylePepperoniPizza();} else return null;}}实现一下披萨本身,没披萨开什么加盟店呢:Java代码//从一个抽象披萨类开始,所有的具体披萨都必须派生自这个类 public abstract class Pizza {String name; //每个披萨都有名称,面团类型,一套佐料String dough;String sauce;ArrayList toppings = new ArrayList();void prepare() {System.out.println("Preparing " + name);System.out.println("Tossing dough...");System.out.println("Adding sauce...");System.out.println("Adding toppings: ");//准备工作需要以特定的顺序进行for (int i = 0; i < toppings.size(); i++) {System.out.println(" " + toppings.get(i));}}void bake() {}void cut() {}void box() {}public String getName() {return name;}public String toString() {StringBuffer display = new StringBuffer();display.append("---- " + name + " ----\n");display.append(dough + "\n");display.append(sauce + "\n");for (int i = 0; i < toppings.size(); i++) {display.append((String )toppings.get(i) + "\n");}return display.toString();}}现在我们来定义纽约和芝加哥风味的具体子类,并吃些披萨怎么样: Java代码public class NYStyleCheesePizza extends Pizza { public NYStyleCheesePizza() {name = "NY Style Sauce and Cheese Pizza";dough = "Thin Crust Dough";sauce = "Marinara Sauce";toppings.add("Grated Reggiano Cheese");}}public class ChicagoStyleCheesePizza extends Pizza { public ChicagoStyleCheesePizza() {name = "Chicago Style Deep Dish Cheese Pizza";dough = "Extra Thick Crust Dough";sauce = "Plum Tomato Sauce";toppings.add("Shredded Mozzarella Cheese");}//这个芝加哥风味披萨覆盖cut()方法,将披萨切成正方形void cut() {System.out.println("Cutting the pizza into square slices");}}public class PizzaTestDrive {public static void main(String[] args) {//建立2个不同的店PizzaStore nyStore = new NYPizzaStore();PizzaStore chicagoStore = new ChicagoPizzaStore();//下订单Pizza pizza = nyStore.orderPizza("cheese");System.out.println("Ethan ordered a " + pizza.getName() + "\n"); pizza = chicagoStore.orderPizza("cheese");System.out.println("Joel ordered a " + pizza.getName() + "\n");}}认识工厂方法模式的时刻终于到了,工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪个.工厂方法让类把实例化推迟到子类。
Factory Method(工厂方法)Factory Method(工厂方法)属于创建型模式,利用工厂方法创建对象实例而不是直接用 New 关键字实例化。
理解如何写出工厂方法很简单,但理解为什么要用工厂方法就需要动动脑子了。
工厂方法看似简单的将 New 替换为一个函数,其实是体现了面向接口编程的思路,它创建的对象其实是一个符合通用接口的通用对象,这个对象的具体实现可以随意替换,以达到通用性目的。
意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
Factory Method 使一个类的实例化延迟到其子类。
举例子如果看不懂上面的意图介绍,没有关系,设计模式需要在日常工作里用起来,结合例子可以加深你的理解,下面我准备了三个例子,让你体会什么场景下会用到这种设计模式。
换灯泡我自己在家换过灯泡,以前我家里灯坏掉的时候,我看着这个奇形怪状的灯管,心里想,这种灯泡和这个灯座应该是一体的,市场上估计很难买到适配我这个灯座的灯泡了。
结果等我把灯泡拧下来,跑到门口的五金店去换的时候,店员随便给了我一个灯泡,我回去随便拧了一下居然就能用了。
我买这个灯泡的过程就用到了工厂模式,而正是得益于这种模式,让我可以方便在家门口就买到可以用的灯泡。
卡牌对战游戏卡牌对战中,卡牌有一些基本属性,比如攻防、生命值,也符合一些通用约定,比如一回合出击一起等等,那么对于战斗系统来说,应该怎样实例化卡牌呢?如何批量操作卡牌,而不是通用功能也要拿到每个卡牌的实例才能调用?另外每个卡牌有特殊能力,这些特殊能力又应该如何拓展呢?实现任意图形拖拽系统一个可以被交互操作的图形,它可以用鼠标进行拉伸、旋转或者移动,不同图形实现这些操作可能并不相同,要存储的数据也不一样,这些数据应该独立于图形存储,我们的系统如果要对接任意多的图形,具备强大拓展能力,对象关系应该如何设计呢?意图解释在使用工厂方法之前,我们就要创建一个用于创建对象的接口,这个接口具备通用性,所以我们可以忽略不同的实现来做一些通用的事情。
C#设计模式系列:⼯⼚⽅法模式(FactoryMethod)1. ⼯⼚⽅法模式简介1. ⼯⼚⽅法模式简介1.1 定义 ⼯⼚⽅法模式定义⼀个⽤于创建对象的接⼝,让⼦类决定实例化哪⼀个类。
⼯⼚⽅法模式是以⼀个类的实例化延迟到其⼦类。
Factory Method模式⽤于在不指定待创建对象的具体类的情况下创建对象。
Factory Method模式的主要意图是隐藏对象创建的复杂性。
Client通常不指定要创建的具体类,Client将⾯向接⼝或抽象类进⾏编码,让Factory类负责创建具体的类型。
通常Factory类有⼀个返回抽象类或者接⼝的静态⽅法。
Client通常提供某种信息让Factory类使⽤提供的信息来确定创建并返回哪个⼦类。
将创建⼦类的责任抽象出来的好处是允许Client完全⽆需考虑依赖类是如何创建的,这遵守依赖倒置原则(Dependency Inversion Principle,DIP)。
Factory Method模式另外⼀个好处是把负责对象创建的代码集中起来,如果需要修改对象⽣成⽅式,可以轻松定位并更新,⽽不会影响到依赖它的代码。
在⾯向对象编程中,⼀般⽅法是⽤⼀个new操作符产⽣⼀个对象的实例。
但是在⼀些情况下,⽤new操作符直接⽣成对象会带来⼀些问题。
⾸先,要使⽤new运算符创建⼀个对象必须清楚所要创建的对象的类信息,包括类名、构造函数等,⽽有时并不现实。
其次许多类型的对象创建需要⼀系列的步骤,可能需要计算或取得对象的初始设置,选择⽣成那个⼦对象实例,或在⽣成需要的对象之前必须⽣成⼀些辅助功能的对象。
在这些情况下,新对象的建⽴就是⼀个过程,⽽不是⼀个简单的操作。
为轻松⽅便地完成复杂对象的创建,从⽽引⼊了⼯⼚模式。
1.2 使⽤频率 ⾼2. ⼯⼚⽅法模式结构2.1 结构图2.2 参与者 ⼯⼚⽅法模式参与者: Product:Product⾓⾊,定义⼯⼚⽅法所创建的对象的接⼝ ConcreteProduct:具体Product⾓⾊,实现Product接⼝ Factory ° 抽象的⼯⼚⾓⾊,声明⼯⼚⽅法,该⽅法返回⼀个Product类型的对象 ° Factory可以定义⼀个⼯⼚⽅法的默认实现,返回⼀个默认的ConcreteProduct对象。
设计模式之创建类模式——工厂方法模式通用类图:工厂方法模式的优点:1.良好的封装性,代码结构清晰。
一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合。
2.工厂方法模式的扩展性非常优秀。
在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成“拥抱变化”。
3.屏蔽产品类。
这一点非常重要,产品类的实现如何变化,调用者都不需要关系,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不要发生变化。
因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定的。
4.工厂方法模式是典型的解耦框架。
高层模块只需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换父类也没问题。
工厂方法模式的使用场景:1.工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,到那时需要慎重考虑是否要增加一个工厂类进行管理,增加代码的复杂度。
2.需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。
3.工厂方法模式可以用在异构项目中。
4.可以使用在测试驱动开发的框架下。
工厂方法模式的扩展:缩小为简单工厂模式简单工厂模式(Simple Factory Pattern),也叫做静态工厂模式。
在实际项目中,采用该方法的案例还是比较多的,其缺点是工厂类的扩展比较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式。
类图:升级为多个工厂类多工厂模式中,每一个产品类都对应一个创建类,好处就是创建类的职责清晰,而且结构简单,但是给可扩展性和可维护性带来了一定的影响。
为什么这么说呢?如果要扩展一个产品类,就需要建立一个相应的工厂类,这样就增加了扩展的难度。
2创建型模式-----⼯⼚⽅法模式简单⼯⼚模式的不⾜:加⼊新产品的同时需要修改⼯⼚类,违背“开闭原则”。
模式动机:增加⼀个抽象⼯⼚类,再定义具体⼯⼚类来⽣产具体的产品,增加新产品时只需要添加产品类和对应的具体⼯⼚类即可。
由于我们是对抽象⼯⼚进⾏编程,因此可以在不修改抽象⼯⼚的前提下增加新产品。
模式定义:⼯⼚⽅法模式(Factory Method Pattern)⼜称⼯⼚模式、虚构造器。
该模式下,抽象⼯⼚负责创建产品的公共接⼝,具体⼯⼚继承⾃该接⼝来具体⽣产产品,这样就相当于将产品的实例化延迟到⼯⼚⼦类中完成。
模式结构图:模式代码:bt_⼯⼚⽅法模式.h:1 #ifndef FMP_H2#define FMP_H3 #include <iostream>45/*6定义抽象产品类7*/8class Product9 {10public:11virtual ~Product(){}12 };1314/*15定义具体产品类16*/17class ConcreteProduct : public Product18 {19public:20 ConcreteProduct();21 };22 ConcreteProduct::ConcreteProduct()23 {24 std::cout << "创建具体产品" << std::endl;25 }2627/*28定义⼯⼚接⼝29*/30class Factory31 {32public:33virtual ~Factory(){ }34virtual Product* factoryMethod() = 0;35 };3637class ConcreteFactory : public Factory38 {39public:40virtual Product* factoryMethod();41 };42 Product* ConcreteFactory::factoryMethod()43 {44return new ConcreteProduct;45 }4647#endif// FMP_Hbt_⼯⼚⽅法模式.cpp:1 #include "bt_⼯⼚⽅法模式.h"2 #include <iostream>34int main()5 {6 std::cout << "***** ⼯⼚⽅法模式测试 *****" << std::endl;7 Factory* factory = NULL;8 factory = new ConcreteFactory;9 Product* product = NULL;10 product = factory->factoryMethod();1112delete product;13delete factory;1415return0;16 }模式优缺点:客户创建具体产品时只需和具体⼯⼚打交道,⽆需关注产品创建细节;在系统中加⼊新产品时,只需添加产品类和具体⼯⼚类,⽆需修改抽象⼯⼚与抽象产品类,⽽这就意味着⽆需修改与⽤户接⼝,系统扩展性提⾼,符合“开闭原则”。
设计模式之⼯⼚⽅法模式(附实例代码下载)⼯⼚⽅法模式继承了简单⼯⼚模式的优点,还弥补了简单⼯⼚模式的缺陷⼯⼚⽅法模式的定义:定义⼀个⽤于创建对象的接⼝,但是让⼦类决定将哪⼀个类实例化,⼯⼚⽅法模式让⼀个类的实例化延迟到其⼦类简⽽⾔之就是⼯⼚⽅法模式有多个⼦⼯⼚,每个⼦⼯⼚负责⼀个产品的⽣产,这些⼦⼯⼚都有⼀个⽗类:抽象⼯⼚⼯⼚⽅法模式包括四个⾓⾊:1)抽象产品2)具体产品3)抽象⼯⼚4)具体⼯⼚不同的具体⼯⼚可以创建不同的具体产品,当然,在实际使⽤时,具体⼯⼚类在实现⼯⼚⽅法时除了创建具体产品对象之外,还可以负责产品对象的初始化⼯作以及⼀些资源和环境配置⼯作,例如连接数据库,创建⽂件等可以通过配置⽂件来储存具体⼯⼚类的类名,再通过反射机制创建具体的⼯⼚对象,这样在更新的具体⼯⼚时⽆需修改源码,系统扩展更加⽅便实例如下:实例说明:模拟建设⼀个⽇志记录器,包括数据库⽇志记录器,⽂件⽇志记录器1.⽇志记录器接⼝充当抽象产品⾓⾊package⼯⼚⽅法模式;/***@author YB*@version 2019年3⽉16⽇下午3:08:18*//** ⽇志记录器接⼝充当抽象产品⾓⾊*/public interface Logger {public void writelog();//接⼝定义的⽅法}2.数据库⽇志记录器,充当具体产品⾓⾊package⼯⼚⽅法模式;/***@author YB*@version 2019年3⽉16⽇下午3:09:54*//** 数据库⽇志记录器,充当具体产品⾓⾊*/public class Databaselogger implements Logger {@Overridepublic void writelog() {// TODO Auto-generated method stubSystem.out.println("数据库⽇志记录");}}3.⽂件⽇志记录器,充当具体产品⾓⾊package⼯⼚⽅法模式;/***@author YB*@version 2019年3⽉16⽇下午3:11:16*//** ⽂件⽇志记录器,充当具体产品⾓⾊*/public class FileLogger implements Logger{@Overridepublic void writelog() {//实现接⼝⽅法// TODO Auto-generated method stubSystem.out.println("⽂件⽇志记录");}}4.⽇志记录器⼯⼚接⼝,充当抽象⼯⼚⾓⾊package⼯⼚⽅法模式;/***@author YB*@version 2019年3⽉16⽇下午3:13:05*//** ⽇志记录器⼯⼚接⼝,充当抽象⼯⼚⾓⾊*/public interface LoggerFactory {public Logger createLogger();//抽象⼯⼚⽅法}5.数据库⽇志记录器⼯⼚类充当具体⼯⼚⾓⾊package⼯⼚⽅法模式;/***@author YB*@version 2019年3⽉16⽇下午3:14:41*//** 数据库⽇志记录器⼯⼚类充当具体⼯⼚⾓⾊*/public class DatabaseLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {// TODO Auto-generated method stub//链接数据库代码略Logger logger=new Databaselogger();//创建数据库⽇志记录器对象 //初始化数据库⽇志记录器代码略return logger;}}6.⽂件⽇志记录器⼯⼚类充当具体⼯⼚⾓⾊package⼯⼚⽅法模式;/***@author YB*@version 2019年3⽉16⽇下午3:16:57*//** ⽂件⽇志记录器⼯⼚类充当具体⼯⼚⾓⾊*/public class FileLoggerFactory implements LoggerFactory{@Overridepublic Logger createLogger() {// TODO Auto-generated method stubLogger logger=new FileLogger();//创建⽂件⽇志记录器对象//创建⽂件代码略}7.客户端package⼯⼚⽅法模式;/***@author YB*@version 2019年3⽉16⽇下午3:20:06*/public class Client {public static void main(String[] args) {// TODO Auto-generated method stubLoggerFactory loggerFactory;Logger logger;//loggerFactory=new FileLoggerFactory();loggerFactory=(LoggerFactory)XMLUtil.getBean();//引⼊配置⽂件和反射机制logger=loggerFactory.createLogger();logger.writelog();}}8.XMLUtil⼯具类package⼯⼚⽅法模式;import java.io.*;import javax.swing.text.Document;import javax.xml.parsers.*;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.soap.Node;import org.w3c.dom.*;import org.w3c.dom.NodeList;/***@author YB*@version 2019年3⽉15⽇下午7:08:17*/public class XMLUtil {//该⽅法⽤于从XML配置⽂件中提取图表类型,并返回类型名public static Object getBean() {try {//创建⽂档对象DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();DocumentBuilder builder=dFactory.newDocumentBuilder();org.w3c.dom.Document doc;doc=builder.parse(new File("src//⼯⼚⽅法模式//config.xml"));//获取包含图表类型的⽂本节点NodeList nlList= ((org.w3c.dom.Document) doc).getElementsByTagName("className"); org.w3c.dom.Node classNode=nlList.item(0).getFirstChild();String cName=classNode.getNodeValue();//通过类名⽣成实例对象并返回Class<?> c=Class.forName(cName);Object obj=c.newInstance();return obj;}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}9.XML配置⽂件<?xml version="1.0" encoding="UTF-8"?><config><className>⼯⼚⽅法模式.DatabaseLoggerFactory</className></config>抽象⼯⼚⽅法的重载:当然,抽象⼯⼚的⽅法也是可以重载的,在抽象⼯⼚中声明多个重载的⼯⼚⽅法,在具体⼯⼚中实现了这些⼯⼚⽅法,这些⼯⼚⽅法可以包含不同的业务逻辑,以满⾜产品对象的多样化创建需求抽象⼯⼚⽅法的隐藏:在具体⼯⼚类中直接调⽤产品类的业务⽅法,这样在客户端就没有必要调⽤⼯⼚⽅法来创建产品对象了,可以直接使⽤⼯⼚对象即可调⽤所建产品对象中的业务⽅法⼯⼚⽅法模式是使⽤频率最该的设计模式之⼀优点:1)⼯⼚⽅法⽤来创建客户所需产品,同时还向客户隐藏了那种具体产品类将被实例化这⼀细节,⽤户只需关⼼所需产品对应的⼯⼚,⽆需关⼼创建细节,甚⾄⽆需知道具体产品的类名2)基于⼯⼚⾓⾊和产品⾓⾊的多态性设计是⼯⼚⽅法模式的关键,他能够让⼯⼚⾃主确定创建何种产品对象,⽽如何创建这个对象的细节完全封装在具体⼯⼚的内部,⼯⼚⽅法模式之所以被称为多态⼯⼚模式,正是因为所有的具体⼯⼚都有同⼀抽象⽗类⼯⼚3)在系统中加⼊新产品时⽆需修改抽象⼯⼚和抽象产品提供的接⼝,⽆需修改客户端,也⽆需修改其他具体过程和具体产品,⽽只要添加⼀个抽象⼯⼚和抽象产品即可,这样系统的可扩展性将变得⾮常好,完全符合开闭原则缺点:1)添加新产品时需要编写新的具体产品类还有对应的具体⼯⼚类,系统中类的个数会增加,⼀定程度上增加了系统复杂度或额外开销2)引⼊了抽象层,增加了系统的抽象性和理解难度。
工厂方法设计模式工厂方法设计模式是一种创建对象的设计模式,它通过定义一个用于创建对象的接口,而将对象的实际创建工作推迟到子类中。
这样做的好处是,将对象的创建与使用相分离,使得系统能够更灵活地适应变化,同时也符合面向对象设计的开闭原则。
在工厂方法设计模式中,核心的思想是将对象的创建交给工厂类来完成,而客户端只负责使用这些对象。
工厂类通常定义一个工厂方法,用于创建具体的产品对象。
这个工厂方法通常是抽象的,由子类来实现,每个子类都负责创建一种具体的产品。
在具体的实现中,工厂方法设计模式可以分为两个部分:产品类和工厂类。
产品类是需要被创建的对象,它们共同实现了一个抽象接口。
工厂类是用来创建产品对象的类,它通常是一个抽象类,或者是一个接口。
工厂类中定义了一个抽象的工厂方法,用于创建具体的产品对象。
使用工厂方法设计模式的好处有多个。
首先,它能够将对象的创建与使用相分离,使得系统的扩展更加容易。
当需要增加一种新的产品时,只需要编写一个具体的产品类和一个相应的工厂类即可,不需要修改原有的代码。
这样做不仅减少了代码的修改风险,还能够提高代码的复用性。
其次,工厂方法设计模式可以提高系统的灵活性。
通过使用工厂方法,客户端可以通过抽象的接口来引用具体的产品对象,而不需要关心具体的实现细节。
这样一来,客户端可以针对接口编程,而不是针对具体的实现类编程。
这种解耦的设计能够使得系统更加灵活,能够随时切换不同的实现。
再次,工厂方法设计模式还能够提高系统的可测试性。
在使用工厂方法时,可以方便地使用不同的工厂类来创建不同的产品对象。
这样一来,在进行单元测试时,可以通过模拟工厂类的行为来创建需要的产品对象,从而对系统进行测试。
这种方式能够更好地隔离不同的模块,提高测试效率。
工厂方法设计模式在实际的应用中有很多情况。
一个常见的应用场景是在创建复杂对象时。
在创建一个复杂对象时,往往需要涉及到各种不同的过程,包括对象的初始化、依赖的注入、资源的分配等。
设计模式工厂方法模式工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。
工厂方法模式允许类将实例化推迟到子类。
在工厂方法模式中,我们定义一个抽象的工厂类,它包含一个创建产品对象的方法,但不会实现该方法。
然后我们将具体的产品创建交给具体的工厂子类去实现。
工厂方法模式有以下几个角色:- 抽象工厂(AbstractFactory):定义用于创建产品的接口,声明工厂方法。
- 具体工厂(ConcreteFactory):实现抽象工厂中的工厂方法,用于创建具体的产品对象。
- 抽象产品(AbstractProduct):定义产品的接口,声明产品的方法。
- 具体产品(ConcreteProduct):实现抽象产品中定义的方法。
工厂方法模式的优点是:- 具体产品的类名被具体工厂子类的类名所替代,如果需要更换或新增具体产品的类,只需要创建一个新的具体工厂子类即可,不需要修改原有的代码。
- 各个具体工厂子类相互独立,不会影响其他子类。
每个具体工厂子类只需要关心自己负责的具体产品对象的创建即可。
工厂方法模式适用于以下情况:- 客户端不需要知道具体产品类的类名,只需要知道抽象产品类的接口。
- 客户端不需要关心具体产品对象的创建细节,只需要使用产品对象。
- 客户端需要根据不同的条件来创建不同的产品对象。
例如,我们可以通过工厂方法模式来创建不同的数据库连接对象,只需要定义抽象数据库连接工厂接口和具体数据库连接工厂子类,以及抽象数据库连接接口和具体数据库连接实现类即可。
这样,客户端只需要关心使用抽象数据库连接接口,而无需关心具体的数据库连接实现。
设计模式之⼯⼚⽅法模式定义定义⼀个⽤于创建对象的接⼝,让⼦类决定实例化哪⼀个类,⼯⼚⽅法使⼀个类的实例化延迟到其⼦类。
结构ProductFactory ,抽象产品⼯⼚,声明了⼀个⼯⼚⽅法,返回⼀个抽象的产品。
Product ,抽象产品,⼯⼚⽅法返回的接⼝类型。
ConcreteProductFactory ,具体⼯⼚,实现抽象⼯⼚接⼝,⼯⼚⽅法返回⼀个具体的产品。
ConcreteProduct ,具体产品,抽象产品的实现,和具体⼯⼚之间⼀⼀对应。
简单实现抽象产品抽象⼯⼚具体⼯⼚和具体产品第⼆个具体⼯⼚实现public interface Product {void show();}public interface ProductFactory {Product newProduct();}public class ConcreteProductFactory1 implements ProductFactory {@Overridepublic Product newProduct() {return new ConcreteProduct1();}public static class ConcreteProduct1 implements Product {@Overridepublic void show() {System.out.println("ConcreteProduct1 show");}}}public class ConcreteProductFactory2 implements ProductFactory {@Overridepublic Product newProduct() {return new ConcreteProduct2();}public static class ConcreteProduct2 implements Product {客户端每⼀种具体的⼯⼚创建对应的具体的产品。
设计模式-⼯⼚⽅法模式前⾔点击查看:如果你对⼯⼚模式这个概念不是很理解,建议:如果你对.net反射机制不了解,建议:⼯⼚⽅法模式描述⼀下⼯⼚⽅法的概要:简单⼯⼚模式是要在⼯⼚类中通过数据来做个决策,在⼯⼚类中的多个类中实例化出来其中⼀个要⽤到的类,做运算。
⽽⼯⼚⽅法模式则是他的⼀个聪明的扩展,不在⼯⼚类中做决策,⽽是把这个决策推迟到每个⽤到他的地⽅。
等待使⽤的类库代码:///<summary>/// Live类///</summary>public abstract class Live{public abstract void Action();}///<summary>/// Music类///</summary>public class Music : Live{public override void Action(){Console.WriteLine("哼哼哈嘿,快使⽤刷结棍!");}}///<summary>/// Bread类///</summary>public class Bread : Live{public override void Action(){Console.WriteLine("努⼒,⾯包会有的,鸡蛋也会有的。
");}}⼯⼚⽅法实例化类:///<summary>/// LiveFactory类///</summary>public abstract class LiveFactory{public abstract Live Create();}///<summary>/// MusicFactory类///</summary>public class MusicFactory : LiveFactory{public override Live Create(){return new Music();}}///<summary>/// BreadFactory类///</summary>public class BreadFactory : LiveFactory{public override Live Create(){return new Bread();}}如何使⽤⼯⼚类选择创建实例(反射优化):public static void Main(string[] args){LiveFactory liveFactory = new MusicFactory();Live musicLive = liveFactory.Create();musicLive.Action();Console.ReadLine();//使⽤反射优化,修改变量就可得到想要的结果,⽽不必修改代码string strfactoryName = "BreadFactory";LiveFactory factory;factory = (LiveFactory)Assembly.Load("设计模式").CreateInstance("设计模式.⼯⼚⽅法模式." + strfactoryName);Live live = factory.Create();live.Action();Console.ReadLine();}使⽤此模式:降低调⽤端的耦合度,并且对于⼯⼚来说,是可以扩展的,以后如果想过另外的⼀种⽣活⽅式,只需要再增加⼀个⼯⼚类的实现就可以。