• 设计模式-工厂模式


    一、概述

    回顾:MySQL存储引擎如何建立个人博客

    个人博客:后台建站,适合java程序员

    什么是工厂模式?

    工厂模式(Factory Pattern)是最常见的一种设计模式之一。它主要是提供一种创建对象的最佳方法!

    为什么要学习工厂模式?

    与通过new来创建对象不同,使用工厂模式创建对象不会对客户端暴露创建逻辑,并且是通过统一个共同的接口指向新创建的对象。同事工厂模式能将创建对象的代码集中在一个对象或者方法中,可以避免代码中的重复,并且更方便维护。面向接口编程,这样的代码更具有弹性,可以应对未来的扩展。

    二、认识工厂模式

    案例:假设你有一个Pizza店,每天要做出不同口味的Pizza。

    假设我们有两种口味Pizza

    /*
     * 抽象的Pizza类,Pizza制作一般包括准备,烘烤,切块,包装。
     */
    public abstract class Pizza{
    	 // Pizza名称
    	 protected String name;
    	 // 面团类型
    	 protected String dough;
    	 // 酱料
    	 protected String sauce;
    	 // 芝士
    	 protected String cheese;
    	 // 蛤蜊
    	 protected String clam;
    	 // 佐料
    	 protected List toppings = new ArrayList();
    	
    	// 准备
    	public  void prepare() {
    		System.out.print("准备食材,添加调料:");
    		for (int i = 0; i < toppings.size(); i++) {
    			System.out.print(toppings.get(i)+" ");
    		}
    	};
    	// 烘烤
    	public  void bake() {
    		System.out.println("烘烤20分钟...");
    	};
    	// 切块
    	public void cut() {
    		System.out.println("切成x块...");
    	};
    	// 包装
    	public void box() {
    		System.out.println("包装...");
    	}
     	// setter 和 getter方法省略
    }
    
    

    芝加哥风味的芝士Pizza

    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");
    
    	}	
    	public void cut() {
    		System.out.println("Cut the pizza into square slices");
    	}
    }
    

    纽约风味的蔬菜Pizza

    public class NyStyleVeggiePizza extends Pizza{
    	public NyStyleVeggiePizza() {
    		name = "NY style Sauce and Veggie Pizza";
    		dough = "Thin Crust Dough";
    		sauce = "Marinara Sauce";
    		toppings.add("Grated Reggiano Veggie");
    	}
    }
    

    纽约风味的芝士Pizza

    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");
    	}
    }
    

    通过new创建对象

    // 创建一个纽约风味的芝士Pizza
    NyStyleCheesePizza nyPizza = new NyStyleCheesePizza();
    

    当使用new得到一个对象时,确实得到了一个具体类,是针对具体类实现,而不是接口。代码绑定具体类会导致代码脆弱,更缺乏弹性。

    简单工厂

    public class SimplePizzaFactory {
    	public Pizza createPizza(String type) {
    		Pizza pizza = null;
    		if (type.equals("NyStyleCheesePizza")) {
    			return new NyStyleChieesePizza();
    		} else if(type.endsWith("ChicagoStyleCheesePizza")) {
    			return new ChicagoStyleCheesePizza();
    		}else {
    			return null;
    		}
    	}
    }
    
    // 创建简单工厂对象
    SimplePizzaFactory pizzaFactory = new SimplePizzaFactory();
    // 创建Pizza对象
    NyStyleChieesePizza myPizza = pizzaFactory.createPizza("NYStyleChieesePizza");
    

    简单工厂将对象的创建过程进行了封装,用户不需要知道具体的创建过程,只需要调用工厂类获取对象即可。

    这种简单工厂的写法是通过if else来判断对象创建过程的。简单工厂只是把new对象的问题转移到另一个类中在实际使用过程中,违背了 开放-关闭原则,当然有些情况下可以通过反射调用来弥补这种不足。

    工厂方法模式

    定义:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

    // 抽象的Pizza工厂
    public abstract class PizzaFactory {
    	public Pizza getPizza(String type) {
    		Pizza pizza;
    		pizza = createPizza(type);
    		pizza.prepare();
    		pizza.bake();
    		pizza.cut();
    		pizza.box();
    		
    		return pizza;
    	}
    	protected abstract Pizza createPizza(String pizza);
    }
    
    
    // 纽约Pizza工厂(芝加哥pizza工厂跟这个类似)
    public class NYPizzaFactory extends PizzaFactory {
    
    	protected Pizza createPizza(String type) {
    		if (type.equals("NyStyleChieesePizza")) {
    			return new NyStyleCheesePizza();
    		} else if (type.equals("NyStyleVeggiePizza")) {
    			return new NyStyleVeggiePizza();
    		}else {
    			return null;
    		}
    	}
    }
    

    通过工厂方法创建对象

    PizzaFactory pizzaFactory = new NYPizzaFactory();
    // 创建一个蔬菜披萨
    Pizza pizza = pizzaFactory.createPizza("NyStyleVeggiePizza");
    

    当使用工厂方法创建对象时,是在编写具体工厂类时决定创建的对象时哪一个,选择使用哪个工厂类,自然就决定了十几创建的是哪个对象。尽管只有一个具体工厂,工厂方法还是非常有用的!因为它将对象从“实现”从“使用”中解耦如果增加对象或者改变对象,工厂是不会受到影响的

    抽象工厂模式

    定义:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

    抽象原料工厂

    // 为了简化, 这里的原料用字符串表示,其实每个原料应该用一个类表示
    public interface PizzaIngredientFactory {
    	public String createDough();
    	public String createSauce();
    	public String createChieese();
    	public String[] createVeggies();
    	public String createPepperoni();
    }
    

    芝士pizza原料工厂

    public class CheesePizzaIngredientFactory implements PizzaIngredientFactory {
    
    	public String createDough() {
    		return "薄地壳比萨生面团";
    	}
    
    	public String createSauce() {
    		return "纽约专用蘸料";
    	}
    
    	public String createChieese() {
    		return "Reggiano干酪";
    	}
    
    	public String[] createVeggies() {
    		 
    		return new String[]{"洋葱","生菜","香菇"};
    	}
    	public String createPepperoni() {
    		return "意大利辣香肠";
    	}
    }
    
    

    创建pizza工厂

    public class ChinaPizzaFactory extends PizzaFactory {
    	
    	public Pizza createPizza(String type) {
    		Pizza pizza = null;
    		PizzaIngredientFactory ingredientFactory = new ChinaPizzaIngredientFactory();
    		if(type.equals("cheese")) {
    			pizza = new CheesePizza(ingredientFactory);
    			pizza.setName("中国芝士pizza");
    		}else if (type.equals("clam")) {
    			pizza = new ClamPizza(ingredientFactory);
    			pizza.setName("中国蛤蜊pizza");
    		}
    		return pizza;
    	}
    }
    
    
     // 具体的Pizza类
    public class ClamPizza extends Pizza {
    	PizzaIngredientFactory ingredientFactory;
    	
    	public ClamPizza(PizzaIngredientFactory pizzaIngredientFactory) {
    		this.ingredientFactory = pizzaIngredientFactory;
    	}
    
    	public void prepare() {
    		System.out.println("Preparinging" + name);
            // 根据pizza本身的特点,从工厂中获取自己需要的原料
    		dough = ingredientFactory.createDough();
    		sauce = ingredientFactory.createSauce();
    		clam = ingredientFactory.creatClam();
    	}
    }
    

    创建一个中国蛤蜊pizza

    // 创建一个Pizza工厂
    PizzaFactory pizzaFactory = new ChinaPizzaFactory();
    Pizza clamPizza = pizzaFactory.createPizza("clam");
    

    抽象工厂模式将'对象' 与 ‘’组成对象或者对象依赖的类‘’解耦。

    三、对比与分析

    通过new来创建对象是面向具体类编程,扩展性差!

    简单工厂把全部的事情都在一个地方处理完了,但是当有新增或者修改的对象类时,很难进行扩展,违反了开闭原则。简单工厂并不能算是工厂模式,而是一种编程习惯,或者是一种方法的封装,并不具备弹性。

    工厂方法是创建一个框架,让子类决定如何实现。虽然可能导致类会变多,代码稍微复杂,但是这样做最大的好处是更具有弹性。

    工厂模式的好处:将创建对象的代码集中在一个对象或者方法中,可以避免代码中重复的代码,并且方便以后的维护。依赖接口,而不是具体的类。

    如何选择?

    当需要将对象家族和具体的对象集合结合起来时,可以使用抽象工厂。

    当需要将客户代码从需要实例化的具体类中解耦,或者目前还不中知道将来实例化哪些具体类时,可以使用工厂方法。

  • 相关阅读:
    centos6.8升级python3.5.2
    钓鱼
    斯诺登的密码
    模板,堆,小根堆
    哥德巴赫猜想(升级版)
    哥德巴赫猜想
    线性筛素数
    乒乓球
    数的重心模板
    笨小猴
  • 原文地址:https://www.cnblogs.com/liqiangchn/p/9147619.html
Copyright © 2020-2023  润新知