设计模式-工厂模式
工厂模式(Factory Pattern)
工厂模式(Factory Pattern):封装对象的创建,处理创建对象的细节。
工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样客户程序中超类的代码就和子类对象的创建部分解耦了
工厂方法分为:简单工厂(静态工厂)、工厂方法、抽象工厂。
几种方式的对比:
简单工厂vs工厂模式:
简单工厂把全部的事情在一个地方做完了,而工厂模式是一个创建框架,让子类决定如何实现
抽象工厂vs工厂模式:
抽象工厂的方法经常以工厂方法的方式实现,抽象工厂的任务是定义一个负责创建一组产品的接口。
工厂方法使用继承,抽象工厂使用组合。
工厂方法只是用来创建一种产品,而抽象工厂创建的是一个产品家族。
使用工厂模式意味着需要扩展一个类并覆盖它的工厂方法。抽象工厂提供了一个创建产品家族的抽象类型,类型的子类定义了产品生产的方式。
简单工厂(静态工厂)结构:
简单工厂模式(Simple Factory Pattern):定义一个工厂类,根据不同的参数,创建并返回不同的类。其中这些类具有一个公共的父类或是一个接口。
Factory:工厂类,内部有是个精通的方法,根据参数选择创建的对象
Product:抽象产品类,其作为具体产品的父类,负责定义产品的公共接口
ConcreteProduct:具体产品类,有多个,都是继承与抽象产品类,工厂就是创建该类对象
//Product:Pizza抽象产品类 public abstract class Pizza{ /*属性*/ String name; String dough; String sauce; List<String> toppings = new ArrayList<String>(); /*提供方法*/ public String getName() {return name;} public void prepare() {System.out.println("Preparing " + name);} public void bake() {System.out.println("Baking " + name);} public void cut() {System.out.println("Cutting " + name);} public void box() {System.out.println("Boxing " + name);} public String toString() { StringBuffer display = new StringBuffer(); display.append(name).append(dough ).append(sauce ); toppings.stream().forEach(topping->{display.append(topping);}); return display.toString(); } } //Concrete:Pizza具体产品类 public class CheesePizza extends Pizza{ public CheesePizza() { name = "Cheese Pizza"; dough = "Regular Crust"; sauce = "Marinara Pizza Sauce"; toppings.add("Fresh Mozzarella"); toppings.add("Parmesan"); } } //Concrete:Pizza具体产品类 public class VeggiePizza extends Pizza{ public VeggiePizza() { name = "Veggie Pizza"; dough = "Crust"; sauce = "Marinara sauce"; toppings.add("Shredded mozzarella");toppings.add("Grated parmesan");toppings.add("Diced onion");toppings.add("Sliced mushrooms");toppings.add("Sliced red pepper");toppings.add("Sliced black olives"); } } //Factory:Pizza工厂类 public class SimplePizzaFactory{ public Pizza createPizza(String type){ Pizza pizza = null; if("cheese"==type){ pizza = new CheesePizza(); }else if("veggie"==type){ pizza = new VeggiePizza(); } return pizza; } } //调用类 public class PizzaStore { //工厂类 SimplePizzaFactory factory; //创建工厂类 通过构造方法传入 public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; } public Pizza orderPizza(String type) { Pizza pizza; //通过工厂类取得Pizza实例 pizza = factory.createPizza(type); pizza.prepare();pizza.bake();pizza.cut();pizza.box(); return pizza; } }
工厂方法模式结构:
工厂方法模式:定义一个用来创建对象的接口,让子类决定实例化哪一个类,让子类决定实例化延迟到子类。
//商品抽象 public abstract class Pizza{ /*属性*/ String name; String dough; String sauce; List<String> toppings = new ArrayList<String>(); /*提供方法*/ public String getName() {return name;} public void prepare() {System.out.println("Preparing " + name);} public void bake() {System.out.println("Baking " + name);} public void cut() {System.out.println("Cutting " + name);} public void box() {System.out.println("Boxing " + name);} public String toString() { StringBuffer display = new StringBuffer(); display.append(name).append(dough ).append(sauce ); toppings.stream().forEach(topping->{display.append(topping);}); return display.toString(); } } //Pizza实现类 public class CheesePizza extends Pizza{
//初始化 public CheesePizza() { name = "Cheese Pizza"; dough = "Regular Crust"; sauce = "Marinara Pizza Sauce"; toppings.add("Fresh Mozzarella");toppings.add("Parmesan"); } } //Pizza实现类 public class VeggiePizza extends Pizza{
//初始化 public VeggiePizza() { name = "Veggie Pizza"; dough = "Crust"; sauce = "Marinara sauce"; toppings.add("Shredded mozzarella");toppings.add("Grated parmesan");toppings.add("Diced onion");toppings.add("Sliced mushrooms");toppings.add("Sliced red pepper");toppings.add("Sliced black olives"); } } //工厂接口 public interface PizzaFactory{ public Pizza createPizza(); } //CheesePizza工厂方法 public class CheesePizzaFactory implements PizzaFactory{ @Override public Pizza createPizza() { return new CheesePizza(); } } //VeggiePizza工厂方法 public class VeggiePizzaFactory implements PizzaFactory{ @Override public Pizza createPizza() { return new VeggiePizza(); } } //工厂方法的调用 public class PizzaStore { public Pizza orderVeggiePizza() { VeggiePizzaFactory veggiePizzaFactory = new VeggiePizzaFactory(); //通过工厂类取得Pizza实例 Pizza pizza = veggiePizzaFactory.createPizza(); pizza.prepare();pizza.bake();pizza.cut();pizza.box(); return pizza; } public Pizza orderCheesePizza() { CheesePizzaFactory cheesePizzaFactory = new CheesePizzaFactory(); //通过工厂类取得Pizza实例 Pizza pizza = cheesePizzaFactory.createPizza(); pizza.prepare();pizza.bake();pizza.cut();pizza.box(); return pizza; } }
抽象工厂模式结构:
AbstractFactory:抽象工厂角色,它声明了一组用于创建一种产品的方法,每一个方法对应一种产品,如上述类图中的AbstractFactory就定义了两个方法,分别创建产品A和产品B
ConcreteFactory:具体工厂角色,它实现了在抽象工厂中定义的创建产品的方法,生产一组具体产品,这饿产品构件成了一个产品种类,每一个产品都位于某个产品等级结构中,如上述类图中的ConcreteFactoryA和ConcreteFactoryB
AbstractProduct:抽象产品角色,为每种产品声明接口,如图中AbstractProductA、AbstractProductB
ConcreteProduct:具体产品角色,定义了工厂生产的具体产品对象,实现抽象产品接口声明的业务方法,如图中ConcreteProductA1、ConcreteProductA2、ConcreteProductB1、ConcreteProductB2
//AbstractProduct:抽象产品角色(显示器) public abstract class Display{ public String showMessage(); } //ConcreteProduct:具体产品角色 public class LCDDisplay extends Display{ @Override public String showMessage() { return "LCD Display"; } } //具体产品角色 public class PDPDisplay extends Display{ @Override public String showMessage() { return "PDP Display"; } } //抽象产品角色(键盘) public abstract class Keyboard{ public void press(); } //具体产品角色 public class HuaWeiKeyboard extends Keyboard{ @Override public void press() { System.out.println("Huawei"); } } //抽象工厂角色 public interface ComputerFactory{ public Keyboard createKeyboard(); public Display createDisplay(); } //具体工厂角色 public class HuaweiComputerFactory implements ComputerFactory{ @Override public Keyboard createKeyboard() { return new HuaWeiKeyboard(); } @Override public Display createDisplay() { return new LCDDisplay(); } } //具体工厂角色 public class OtherComputerFactory implements ComputerFactory{ @Override public Keyboard createKeyboard() { return new HuaWeiKeyboard(); } @Override public Display createDisplay() { return new PDPDisplay(); } }
设计原则:
1、依赖倒置原则
不能让高层组件依赖底层组件,而且不管高层、底层组件,两者都应该依赖于抽象。
如何避免违反依赖倒置原则:
①变量不可以持有具体类的引用。
如果使用new,则会持有具体类的引用,可以用工程来避开这样的做法
② 不要让类派生自具体类。
如果派生自具体类,你就会依赖具体类(请派生自一个抽象类或接口)
③不要覆盖基类中已实现的方法。
如果覆盖基类已实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该由所有的子类共享。
优点:
简单工厂模式优点:
集中封装了对象的创建,使得要更换对象时不需要做大的改动就可实现,降低了客户端程序与产品对象的耦合。
简单工厂模式最大的优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
工厂方法模式优点:
集中封装了对象的创建,使得要更换对象时不需要做大的改动就可实现,降低了客户端程序与产品对象的耦合。
工厂模式是简单工厂模式的进一步抽象和推广。它遵循了“开放—封闭”原则。
抽象工厂模式优点:
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。
所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。
缺点:
简单工厂模式缺点:
是没有遵守开放—封闭原则。所谓的“开放-封闭”原则就是开放接口,封闭修改。
如果将来需要添加一个开方的算法,那么,在简单工厂模式中,就必须在简单工厂类中添加相应的判断语句!
另外,在简单工厂类中利用了Switch语句,这对程序的扩展本身就不不利。
工厂方法模式缺点:
工厂方法把简单工厂的内部逻辑判断转移到了客户端代码来执行;
每增加一产品就要增加一个产品工厂的类,增加了额外的开发量。
抽象工厂模式缺点:
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改,对“开闭原则”的支持呈现倾斜性。
所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。
应用场景:
消费者不关心它所要创建对象的类(产品类)的时候。
消费者知道它所要创建对象的类(产品类),但不关心如何创建的时候。