怎样建立自己的销售网站,wordpress当前分类名,郑州做网站公司电话,合作建站方案之前我们一直在使用new操作符#xff0c;但是实例化这种行为并不应该总是公开的进行#xff0c;而且初始化经常会造成耦合问题#xff0c;工厂模式将摆脱这种复杂的依赖#xff0c;本次内容包括简单工厂#xff0c;工厂方法和抽象工厂三种情况。 1 2 3 4 5 6 Duck duck但是实例化这种行为并不应该总是公开的进行而且初始化经常会造成耦合问题工厂模式将摆脱这种复杂的依赖本次内容包括简单工厂工厂方法和抽象工厂三种情况。 1 2 3 4 5 6 Duck duck if(a){ ducknew Duck1(); }else{ ducknew Duck2(); }
如上面代码中使用new实例化一个类时使用的是实现而不是接口代码捆绑着具体类会导致代码更脆弱缺乏弹性后续的维护、修改等操作容易出错。
使用new操作符会造成的问题
1.如果你针对接口编程你可以利用多态实现该接口并没有太大问题2.但是如果代码中使用了很多具体类一旦加入新的类就必须改变代码这就违反了开放-关闭原则。
项目举例
假设你有一家 pizza 店你有很多种 pizza要在系统中显示你所有pizza种类。 实现这个功能并不难 使用普通方式实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class PizzaStore { Pizza orderPizza(String type) { Pizza pizza null; if (type.equals(cheese)) { pizza new CheesePizza(); } else if (type.equals(clam)) { pizza new ClamPizza(); } else if (type.equals(veggie)) { pizza new VeggiePizza(); } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
但是如果新上市一种pizza或者下架一种pizza你就需要修改这段代码这样就没有做到对修改关闭。 简单工厂 于是我们使用之前学到的知识找到变化的代码和不变的代码进行封装了 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class SimpleFactory { public Pizza createPizza(String type) { Pizza pizza null; if (type.equals(cheese)) { pizza new CheesePizza(); } else if (type.equals(clam)) { pizza new ClamPizza(); } else if (type.equals(veggie)) { pizza new VeggiePizza(); } return pizza; } } public class PizzaStore { SimpleFactory simpleFactory; public PizzaStore(SimpleFactory simpleFactory) { this.simpleFactory simpleFactory; } Pizza orderPizza(String type) { Pizza pizza null; pizza simpleFactory.createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
这么做的好处看起来好像只是把原来的代码放进到另外一个类中但是当以后出现变化时自需要修改这个类就可以并且这样做的好处还在于可能现在只有客人点餐才会用到这段代码如果可以点外卖的话仍然可以用这段代码代码得到了复用 上面的简单工厂并不是一个真正的模式只是一种编程习惯这个不能算工厂模式不过也算是基本满足需求。
工厂方法模式
背景更新假如现在你要开分店各种加盟商进来后他们都要开发符合本地口味的pizza那就需要各个地方都有一个工厂也就是每个地方继承SimpleFactory类但是每个工厂并不是完全使用你原来的烘培方法。
工厂方法模式类图如下 对应代码· 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public abstract class PizzaStore { Pizza orderPizza(String type) { Pizza pizza null; pizza createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } protected abstract Pizza createPizza(String type); } public class NYPizzaStore extends PizzaStore { Override protected Pizza createPizza(String type) { if (type.equals(cheese)) { return new NYCheesePizza(); } return null; } } public class ChicagoPizzaStore extends PizzaStore { Override protected Pizza createPizza(String type) { if (type.equals(cheese)) { return new ChicagoCheesePizza(); } return null; } }
现在订购这些订单时自需要实例化各自风格的工厂就算都是芝士披萨也是来自不同商店口味的。 总结
工厂方法模式定义了一个创建对象的接口但由子类决定要实例化的是哪一个工厂方法让类把实例化推迟到子类工厂方法模式的优点在于帮助产品从使用中分离从使用中解耦。和简单工厂的区别两者类似但是在于createPizza方法工厂方法让每个上篇自行负责而简单工厂使用的则是PizzaStore对象。简单工厂把所有的事情在一个地方干完了然而工厂方法则是写了一个框架让子类具体实现PizzaStore作为工厂的orderPizza方法提供了一个一般的框架以便创建披萨其具体依赖工厂的方法来创建具体的披萨。两者都实现了不让创建对象的代码到处乱跑。
看看对象依赖情况原来的PizzaStore依赖于所有的Pizza对象当这些对象发生改变时可能会影响到PizzaStorePizzaStore时依赖具体类的PizzaStore就是高层组件Pizza各种对象就是低层组件但是设计原则有一条是依赖抽象不要依赖具体类 而使用工厂方法之后就不在出现这种依赖很多具体类的情况了。 现在背景有变有些加盟店使用低价原料来增加利润你必须采取一些手段以免毁掉你的披萨店品牌。 你打算建造一家成产原料的工厂并将原料运送到各家加盟店那么剩下最后一个问题不同的区域原料是不一样的对于两个加盟店给出了两组不同的原料。 类图 建造原料工厂 我们要建造一个工厂来生产原料这个工厂负责创建原料家族中的每一种原料。 1 2 3 4 5 6 7 8 public interface PizzaIngredientFactory { public Dough createDough(); public Sauce createSauce(); public Cheese createCheese(); public Veggies[] createVeggies(); public Pepperoni createPepperoni(); public Clams createClams(); }
要做的事情是 1.为每个区域建造一个工厂你需要创建一个继承自PizzaIngredientFactory的子类来实现每一个创建方法。 2.实现一组原料类供工厂使用例如RegianoCheeseRedPeppers,ThickCrustDough.这些类可以在何时的区域间共享。 3.然后你仍然需要将这一切组织起来将新的原料工厂整合进旧的PizzaStore代码中。
创建纽约的原料工厂 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class NYPizzaIngredientFactory implements PizzaIngredientFactory{ Override public Dough createDough() { return null; } Override public Sauce createSauce() { return null; } Override public Cheese createCheese() { return null; } Override public Veggies[] createVeggies() { return new Veggies[0]; } Override public Pepperoni createPepperoni() { return null; } Override public Clams createClams() { return null; } }
重做披萨 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 abstract class Pizza{ String name; Dough dough; Sauce sauce; Veggies veggies[]; Cheese cheese; Pepperoni pepperoni; Clams clams; abstract void prepare(); void cut(){ System.out.println(Cutting the pizza into diagonal slices); } void box(){ System.out.println(Place pizza in official PizzaStore box); } void setName(String name){ this.namename; } public String getName(){ return name; } public void toString2(){ //这里打印披萨的代码 } }
继续重做披萨 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class CheesePizza extends Pizza { //这里组合了一个PizzaIngredientFactory对象的引用用于提供不同的原料 PizzaIngredientFactory ingredientFactory; /** * 通过传入一个PizzaIngredientFactory原料工厂我们可以在制作Pizza的时候动态的产生所需要的原料 * param ingredientFactory */ public CheesePizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory ingredientFactory; } void prepare() { System.out.println(Preparing name); dough ingredientFactory.createDough(); sauce ingredientFactory.createSauce(); cheese ingredientFactory.createCheese(); } }
再回到披萨店 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class NYPizzaStore extends PizzaStore { protected Pizza createPizza(String item) { Pizza pizza null; PizzaIngredientFactory ingredientFactory new NYPizzaIngredientFactory(); if (item.equals(cheese)) { pizza new CheesePizza(ingredientFactory); pizza.setName(New York Style Cheese Pizza); } else if (item.equals(veggie)) { pizza new VeggiePizza(ingredientFactory); pizza.setName(New York Style Veggie Pizza); } else if (item.equals(clam)) { pizza new ClamPizza(ingredientFactory); pizza.setName(New York Style Clam Pizza); } else if (item.equals(pepperoni)) { pizza new PepperoniPizza(ingredientFactory); pizza.setName(New York Style Pepperoni Pizza); } return pizza; } }
我们做了些什么 我们引入新类型的工厂也就是所谓的抽象工厂来创建披萨原料家族。 通过抽象工厂所提供的接口可以创建产品的家族利用这个接口书写代码我们的代码将从实际工厂解耦以便在不同上下文中实现各式各样的工厂制造出各种不同的产品。
定义抽象工厂模式
抽象工厂模式提供一个接口用于创建相关或依赖对象的家族而不需要明确指定具体类。 工厂方法与抽象工厂
抽象工厂的每个方法都实际上看起来像工厂方法方法声明成抽象子类方法去覆盖这些方法去创建对象。 抽象工厂的任务是定义一个负责创造一组产品的接口每个方法就是创建一种产品这就是工厂方法所以在抽象工厂中利用工厂方法来实现生产方法是自然的。
对比
两者都是用来创建对象但是工厂方法使用的是继承而抽象工厂使用的是对象的组合。比如工厂方法创建pizza是各种PizzaStore继承后覆盖createPizza()方法实现的让客户从具体类型中解耦。但是对于抽象工厂提供了一个用来创建一个产品家族的抽象类型这个类型的子类定义了产品被产生的方法要想使用这个工厂必须实例化它然后将它传入一些针对抽象类型所写的代码中。比如PizzaIngredientFactory这个接口定义了一堆原料的做法而对于纽约的原料加工厂先实现这些接口然后纽约的商店实例化这个原料加工厂就保证了不同的商店使用到各自不同的原料把客户从所使用的实际产品中解耦。一群还是一个一群产品集合用抽象工厂具体哪些类中可以确定一个抽象类子类继承实现使用工厂方法设计原则依赖倒置
依赖倒置原则要依赖抽象不要依赖具体类。高层次的模块不应该依赖于低层次的模块他们都应该依赖于抽象。抽象不应该依赖于具体实现具体实现应该依赖于抽象。
用依赖倒置原则重构代码
下面是一些指导方针来避免违反依赖倒置原则
变量不可以持有具体类的引用。如果使用new就会持有具体类的引用你可以改成工厂来避免不要让类派生自具体类如果派生自具体类你就会依赖具体类请派生自抽象接口或者抽象类不要覆盖基类中已经实现的方法如果覆盖那么基类说明就不是一个真正适合被继承的抽象基类中已经实现的方法应该有所有的子类共享
要尽量达到这些原则但不是随时都要遵守 总结
工厂封装对象的创建处理创建对象的细节
静态工厂利用静态方法定义一个简单的工厂。优点不需要创建工厂类的实例化。缺点不能通过继承改变创建方法行为。
简单工厂简单工厂并不是一种设计模式因为只是简单的把创建对象的代码封装起来
工厂模式在父类定义了一个创建对象的接口通过让子类决定创建的对象是什么来达到让对象创建的过程封装的目的。工厂方法让类把实例化推迟到子类
抽象工厂提供一个接口用于创建相关或依赖对象的家族而不需要指明具体的类
工厂方法用来处理对象的创建并将这样的行为封装在子类中。这样客户程序中超类的代码就和子类对象的创建部分解耦了简单工厂vs工厂模式简单工厂把全部的事情在一个地方做完了而工厂模式是一个创建框架让子类决定如何实现抽象工厂vs工厂模式 抽象工厂的方法经常以工厂方法的方式实现抽象工厂的任务是定义一个负责创建一组产品的接口工厂方法使用继承抽象工厂使用组合工厂方法只是用来创建一种产品而抽象工厂创建的是一个产品家族使用工厂模式意味着需要扩展一个类并覆盖它的工厂方法。抽象工厂提供了一个创建产品家族的抽象类型类型的子类定义了产品生产的方式