zoukankan      html  css  js  c++  java
  • 设计模式-工厂模式

    一、概述

    回顾: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来创建对象是面向具体类编程,扩展性差!

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

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

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

    如何选择?

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

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

  • 相关阅读:
    关于同余最短路
    【水】关于 __attribute__
    题解【AtCoder
    一些简单图论问题
    浅谈简单动态规划
    关于博客园主题(美化博客园)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第47章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第46章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第45章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第44章 读书笔记(待更新)
  • 原文地址:https://www.cnblogs.com/liqiangchn/p/9147619.html
Copyright © 2011-2022 走看看