设计模式之工厂模式及抽象工厂模式
- 工厂方法模式以及抽象工厂模式
- 工厂模式案例一
- 工厂模式案例二
- 小结
工厂方法模式以及抽象工厂模式
- 工厂方法 : 定义一个创建对象的接口(抽象方法),让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程(实例化)延迟到子类进行。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
- 抽象工厂: 提供一个创建一系列相关或相互依赖对象的接口(对象族),而无需指定它们具体的类。抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
工厂模式案例一
通过烘烤披萨并且完善相关的订单系统来看工厂模式,披萨有各种各样的,用户通过点不同的披萨,后台不断的完成相应的工作,即准备相应的披萨、烘烤、切片、打包。
(1)首先看一个不好的设计方案 :
各种Pizza类的父类
package factory.Bad.pizza;
/**
* Pizza超类
*/
public abstract class Pizza {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//抽象方法,子类具体不同的实现
public abstract void prepare();
//不需要子类实现的(抽象类里面已经实现了)
public void bake(){
System.out.println(name + " baking !");
}
public void cut(){
System.out.println(name + " cutting !");
}
public void box(){
System.out.println(name + " boxing !");
}
}
然后是几个Pizza子类:
package factory.Bad.pizza;
public class CheesePizza extends Pizza {
@Override
public void prepare() {
setName("CheesePizza");
System.out.println(getName() + " preparing!");
}
}
package factory.Bad.pizza;
public class GreekPizza extends Pizza {
@Override
public void prepare() {
setName("GreekPizza");
System.out.println(getName() + " preparing!");
}
}
package factory.Bad.pizza;
public class PepperPizza extends Pizza {
@Override
public void prepare() {
setName("PepperPizza");
System.out.println(getName() + " preparing!");
}
}
然后是下单的类:
package factory.Bad.order;
import factory.Bad.pizza.CheesePizza;
import factory.Bad.pizza.GreekPizza;
import factory.Bad.pizza.PepperPizza;
import factory.Bad.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class OrderPizza {
//直接在构造函数中
public OrderPizza() {
Pizza pizza = null;
String orderType;
do{
orderType = getType();
if(orderType.equals("cheese")){
pizza = new CheesePizza();
}else if(orderType.equals("greek")){
pizza = new GreekPizza();
}else if(orderType.equals("pepper")){
pizza = new PepperPizza();
}else { //输入异常
break;
}
//开始烘烤包装
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}while(true);
}
//输入相应的种类
private String getType() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type : ");
String str = null;
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
测试类:
package factory.Bad.test;
import factory.Bad.order.OrderPizza;
public class MyTest {
public static void main(String[] args) {
OrderPizza orderPizza = new OrderPizza();
}
}
测试情况
- 上面的测试方案的不好之处在于如果我们想增加新的披萨,就需要修改订单中的if esle语句,每次增加,都要修改
- 所以对于可能以后会变化的地方,我们可以封装成另一个类,抽取出来,降低耦合度。
(2)使用简单工厂模式
我们可以把需要改变的那部分抽取出来成为一个类: (所以简单工厂模式很简单,只是把之前的可以变化的部分抽取出来)
我们看OrderPizza类和SimplePizzaFactory类,和上面的代码只有这里有变化:
package factory.SimpleFactory.factory;
import factory.SimpleFactory.pizza.CheesePizza;
import factory.SimpleFactory.pizza.GreekPizza;
import factory.SimpleFactory.pizza.PepperPizza;
import factory.SimpleFactory.pizza.Pizza;
public class SimplePizzaFactory {
/**
* 这个方法也可以写成 静态的,,这样在 OrderPizza类中就不需要传入这个类的对象了
* (不过写成静态的也有不好的地方,不能通过继承来改变创建的行为)
*/
public Pizza createPizza(String orderType){
Pizza pizza = null;
if(orderType.equals("cheese")){
pizza = new CheesePizza();
}else if(orderType.equals("greek")){
pizza = new GreekPizza();
}else if(orderType.equals("pepper")){
pizza = new PepperPizza();
}
return pizza;
}
}
OrderPizza类中要有SimplePizzaFactory类的对象引用
package factory.SimpleFactory.order;
import factory.SimpleFactory.factory.SimplePizzaFactory;
import factory.SimpleFactory.pizza.CheesePizza;
import factory.SimpleFactory.pizza.GreekPizza;
import factory.SimpleFactory.pizza.PepperPizza;
import factory.SimpleFactory.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class OrderPizza {
SimplePizzaFactory simplePizzaFactory;
public OrderPizza(SimplePizzaFactory simplePizzaFactory) {
this.simplePizzaFactory = simplePizzaFactory;
setFactory();
}
//直接在构造函数中
public void setFactory() {
Pizza pizza = null;
String orderType;
do{
orderType = getType();
pizza = simplePizzaFactory.createPizza(orderType);
if (pizza != null) {
//开始烘烤包装
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}while(true);
}
private String getType() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type : ");
String str = null;
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
测试类
package factory.SimpleFactory.test;
import factory.SimpleFactory.factory.SimplePizzaFactory;
import factory.SimpleFactory.order.OrderPizza;
public class MyTest {
public static void main(String[] args) {
OrderPizza orderPizza = new OrderPizza(new SimplePizzaFactory());
}
}
测试效果和之前是一样的。
(3)使用工厂方法模式
上面的方法可以解决耦合的问题,但是如果我们还有很多连锁披萨店,而且各个地方的披萨必须带上自己的特色,那么我们就可以使用工厂方法设计模式。
先看几个有特色的披萨
package factory.FactoryMethod.pizza;
/**
* Pizza超类
*/
public abstract class Pizza {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//抽象方法,子类具体不同的实现
public abstract void prepare();
//不需要子类实现的(抽象类里面已经实现了)
public void bake(){
System.out.println(name + " baking !");
}
public void cut(){
System.out.println(name + " cutting !");
}
public void box(){
System.out.println(name + " boxing !");
}
}
package factory.FactoryMethod.pizza;
public class LDCheesePizza extends Pizza {
@Override
public void prepare() {
setName("LDCheesePizza");
System.out.println(getName() + " preparing !");
}
}
package factory.FactoryMethod.pizza;
public class LDPepperPizza extends Pizza{
@Override
public void prepare() {
setName("LDPepperPizza");
System.out.println(getName() + " preparing!");
}
}
package factory.FactoryMethod.pizza;
public class NYCheesePizza extends Pizza{
@Override
public void prepare() {
setName("NYCheesePizza");
System.out.println(getName() + " preparing !");
}
}
package factory.FactoryMethod.pizza;
public class NYPepperPizza extends Pizza {
@Override
public void prepare() {
setName("NYPepperPizza");
System.out.println(getName() + " preparing!");
}
}
然后就是三个”工厂”,把OrderPizza设计成抽象类,然后LDOrderPizza和NYOrderPizza都继承自OrderPizza:
package factory.FactoryMethod.order;
import factory.FactoryMethod.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public abstract class OrderPizza {
public OrderPizza(){
Pizza pizza = null;
String orderType;
do{
orderType = getType();
pizza = createPizza(orderType);
if (pizza != null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}while(true);
}
//子类实现
public abstract Pizza createPizza(String orderType);
private String getType() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type : ");
String str = null;
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
package factory.FactoryMethod.order;
import factory.FactoryMethod.pizza.NYCheesePizza;
import factory.FactoryMethod.pizza.NYPepperPizza;
import factory.FactoryMethod.pizza.Pizza;
public class NYOrderPizza extends OrderPizza {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")){
pizza = new NYCheesePizza();
}else if(orderType.equals("pepper")){
pizza = new NYPepperPizza();
}
return pizza;
}
}
package factory.FactoryMethod.order;
import factory.FactoryMethod.pizza.LDCheesePizza;
import factory.FactoryMethod.pizza.LDPepperPizza;
import factory.FactoryMethod.pizza.Pizza;
public class LDOrderPizza extends OrderPizza {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")){
pizza = new LDCheesePizza();
}else if(orderType.equals("pepper")){
pizza = new LDPepperPizza();
}
return pizza;
}
}
测试类:
package factory.FactoryMethod.test;
import factory.FactoryMethod.order.LDOrderPizza;
import factory.FactoryMethod.order.NYOrderPizza;
import factory.FactoryMethod.order.OrderPizza;
public class MyTest {
public static void main(String[] args) {
// OrderPizza orderPizza = new LDOrderPizza();
OrderPizza orderPizza = new NYOrderPizza();
}
}
测试纽约的披萨效果
(4)使用抽象工厂模式
就是明确的指定一个抽象工厂,以及下面的子工厂,具体设计如下:
先看三个工厂
package factory.AbstractFactory.factory;
import factory.AbstractFactory.pizza.Pizza;
public interface AbsFactory {
public Pizza createPizza(String orderType);
}
package factory.AbstractFactory.factory;
import factory.AbstractFactory.pizza.LDCheesePizza;
import factory.AbstractFactory.pizza.LDPepperPizza;
import factory.AbstractFactory.pizza.Pizza;
public class LDFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")){
pizza = new LDCheesePizza();
}else if(orderType.equals("pepper")){
pizza = new LDPepperPizza();
}
return pizza;
}
}
package factory.AbstractFactory.factory;
import factory.AbstractFactory.pizza.NYCheesePizza;
import factory.AbstractFactory.pizza.NYPepperPizza;
import factory.AbstractFactory.pizza.Pizza;
public class NYFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")){
pizza = new NYCheesePizza();
}else if(orderType.equals("pepper")){
pizza = new NYPepperPizza();
}
return pizza;
}
}
然后是点单系统: 里面有总工厂对象的引用:
package factory.AbstractFactory.order;
import factory.AbstractFactory.factory.AbsFactory;
import factory.AbstractFactory.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class OrderPizza {
AbsFactory absFactory;
public OrderPizza(AbsFactory absFactory) {
this.absFactory = absFactory;
setFactory();
}
private void setFactory() {
Pizza pizza = null;
String orderType;
do {
orderType = getType();
pizza = absFactory.createPizza(orderType);
if (pizza != null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
break;
}
}while (true);
}
private String getType() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type : ");
String str = null;
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
测试类:
package factory.AbstractFactory.test;
import factory.AbstractFactory.factory.LDFactory;
import factory.AbstractFactory.factory.NYFactory;
import factory.AbstractFactory.order.OrderPizza;
public class MyTest {
public static void main(String[] args) {
// OrderPizza orderPizza = new OrderPizza(new LDFactory());
OrderPizza orderPizza2 = new OrderPizza(new NYFactory());
}
}
运行效果和工厂模式一样。
工厂模式案例二
再看一个模拟鼠标,键盘,耳麦为产品,惠普,戴尔为工厂的例子。
(1)使用简单工厂模式
Mouse
package factory.practice.SimpleFactory;
public abstract class Mouse {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void display();
}
package factory.practice.SimpleFactory;
public class DellMouse extends Mouse {
public DellMouse(){
setName("DellMouse");
}
@Override
public void display() {
System.out.println(getName() + " ! ");
}
}
package factory.practice.SimpleFactory;
public class HpMouse extends Mouse {
public HpMouse() {
setName("HpMouse");
}
@Override
public void display() {
System.out.println(getName() + " ! ");
}
}
Mouse工厂(根据类型生成不同工厂的鼠标)
package factory.practice.SimpleFactory;
public class MouseFactory {
public static Mouse createMouse(String type){
if(type.equals("dell")){
return new DellMouse();
}else if(type.equals("hp")){
return new HpMouse();
}
return null;
}
}
测试
package factory.practice.SimpleFactory;
import java.io.BufferedInputStream;
import java.util.Scanner;
public class MyTest {
public static void main(String[] args) {
Scanner cin = new Scanner(new BufferedInputStream(System.in));
String type = cin.nextLine();
Mouse mouse = MouseFactory.createMouse(type);
mouse.display();
}
}
效果
(2)使用工厂模式
三个工厂
package factory.practice.FactoryMethod;
public interface MouseFactory {
Mouse createMouse();
}
package factory.practice.FactoryMethod;
public class DellMouseFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
}
package factory.practice.FactoryMethod;
public class HpMouseFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new HpMouse();
}
}
其他的鼠标类不变(就不重复贴了)
测试类
package factory.practice.FactoryMethod;
public class MyTest {
public static void main(String[] args) {
MouseFactory mouseFactory = new DellMouseFactory();
mouseFactory.createMouse().display();
}
}
效果
DellMouse !
(3)使用抽象工厂
这个是当我们在抽象工厂中添加多个方法(就是说PC厂商不仅生成鼠标,还要生产键盘),就成为了抽象工厂。
代码就不贴了放在我的github代码仓库
小结
工厂方法要多加练习,才能在实际项目中好好运用,这里还给出一个讲的好的博客