• 设计模式之工厂模式(二)


    之前已经带大家稍微入门了工厂模式(即简单工厂模式)的方法,没看过的朋友可以移步去查看一番。设计模式之工厂模式(一)。今天我们继续吃着披萨,学习着工厂模式的接下来部分吧。

    加盟披萨店

    我们先前的披萨店已经经营有成,击败了部分竞争者,接下来的计划就是开加盟店。作为经营者,你肯定希望确保加盟店运营的质量,所以希望这些店都是用你那些经过时间考验的代码。

    但是每个地方可能需要不同口味的披萨(比如A地区、B地区、C地区等),这就是开店地点以及该地区披萨美食家口味的影像。

    如果利用先前的简单工厂,那么就是需要创建多个不同的工厂可以使用。代码如下:

    NYPizzaFactory nyFactory = new NYPizzaFactory();
    PizzaStore nyStore = new PizzaStore(nyFactory);
    nyStore.orderPizza("Veggie");
    
    ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
    PizzaStore nyStore = new PizzaStore(chicagoFactory);
    nyStore.orderPizza("Veggie");
    

    给披萨店使用的框架

    在使用简单工厂的时候,我们发现加盟店的确是采用工厂创建披萨,但是其他部分,却开始采用自己的方式。有个做法可以让披萨制作活动局限于PizzaStore类,而同时又能让这些加盟店可以自由地制作该地区的风味。

    所要做的事情呢,就是把之前createPizza()方法放回到PizzaStore中,不过不是单纯的放回来,而是把它设置成抽象方法,然后每个区域创建一个PizzaStore的子类即可。.放出部分代码来看看

    public abstract class PizzaStore {
        public Pizza orderPizza(String type) {
            // 现在createPizza()方法从工厂对象中移回PizzaStore
            Pizza pizza = createPizza(type);
            ...
            return pizza;
        }
        
        // 现在把工厂对象移动到这个方法中
        abstract Pizza createPizza(String type);
    }
    

    现在上面这个就作为超类;让每个域类型都继承这个PizzaStore,每个子类各自决定如何制造披萨。

    允许子类做决定

    我们现在要让createPizza()能够应对各种变化创建正确种类的披萨。做法是让PizzaStore的各个子类负责定义自己的createPizza()方法。所以,我们会得到一些PizzaStore具体的子类,每个子类都有自己的披萨变体,而仍然适合PizzaStore框架,并使用调试好的orderPizza()方法。
    ;

    这时候会有人肯定纳闷了,PizzaStore的子类终究是子类,如何能做决定呢?关于这个方面,要从PizzaStore的orderPizza()方法观点来看,此方法在抽象的PizzaStore内定义,但是只在子类中实现具体类型。

    现在,更进一步地,orderPizza()方法对Pizza对象做了许多事情,但由于Pizza对象是抽象的,orderPizza()并不知道哪些实际的具体类参与进来了。换句话说,这就是解耦(decopule)。

    当orderPizza()调用createPizza()时,就会由具体的披萨店来决定做哪一种披萨。那么,子类是实时做出这样的决定吗?不是,但从orderPizza()角度来看,如果选择在NYStylePizzaStore订购披萨,就是由这个子类决定。

    让我们开一家披萨店吧

    现在我们把加盟店开了。其实我们只需要继承PizzaStore,然后提供createPizza()方法实现自己的披萨风味即可。比如纽约风味:

    // NYPizzaStore扩展PizzaStore,所以拥有orderPizza方法(以及其他方法)
    public class NYPizzaStore extends PizzaStore {
    
    // createPizza()返回一个Pizza对象,由子类全权负责该实例化哪一个具体的Pizza
    	Pizza createPizza(String item) {
    		if (item.equals("cheese")) {
    			return new NYStyleCheesePizza();
    		} else if (item.equals("veggie")) {
    			return new NYStyleVeggiePizza();
    		} else if (item.equals("clam")) {
    			return new NYStyleClamPizza();
    		} else if (item.equals("pepperoni")) {
    			return new NYStylePepperoniPizza();
    		} else return null;
    	}
    }
    

    工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

    如何利用披萨工厂方法订购披萨

    1. 首先,需要取得披萨店的实例。A需要实例化一个ChicagoPizzaStore,而B需要一个NYPizzaStore
    2. 有了各自的PizzaStore,A和B分别调用orderPizza()方法,并传入他们所喜爱的披萨类型
    3. orderPizza()调用createPizza()创建披萨。其中NYPizzaStore实例化的是纽约风味披萨,而ChicagoPizzaStore实例化的是芝加哥风味披萨。createPizza()会创建好的披萨当做返回值。
    4. orderPizza()并不知道真正创建的是哪一个披萨,只知道这是一个披萨,能够被准备、被烘烤、被切片、被装盒、然后提供给A和B

    看看如何根据订单生产这些披萨

    1. 先看看A的订单,首先我们需要一个纽约披萨店:
    // 建立一个NYPizzaStore的实例
    PizzaStore nyPizzaStore = new NYPizzaStore();
    
    1. 现在有了一个店,可以下订单了:
    // 调用nyPizzaStore实例的orderPizza()方法
    nyPizzaStore.orderPizza("cheese");
    
    1. orderPizza()方法于是调用cratePizza()方法
    // 别忘了,工厂方法create-Pizza()是在子类中实现的。在这个例子中,他会返回纽约芝士披萨
    Pizza pizza = createPizza("cheese");
    
    1. 最后,披萨必须经过下列的处理才算成功orderPizza();
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    

    吃披萨咯

    我们需要先有一个比萨,不然披萨店开起来了,结果没有产品,岂不是很尴尬。

    // 从一个抽象披萨类开始,所有的具体披萨都必须派生自这个类
    public abstract class Pizza {
    	String name;
    	String dough;
    	String sauce;
    	ArrayList<String> toppings = new ArrayList<String>();
     
    	void prepare() {
    		System.out.println("Prepare " + name);
    		System.out.println("Tossing dough...");
    		System.out.println("Adding sauce...");
    		System.out.println("Adding toppings: ");
    		for (String topping : toppings) {
    			System.out.println("   " + topping);
    		}
    	}
      
    	void bake() {
    		System.out.println("Bake for 25 minutes at 350");
    	}
     
    	void cut() {
    		System.out.println("Cut the pizza into diagonal slices");
    	}
      
    	void box() {
    		System.out.println("Place pizza in official PizzaStore box");
    	}
     
    	public String getName() {
    		return name;
    	}
    
    	public String toString() {
    		StringBuffer display = new StringBuffer();
    		display.append("---- " + name + " ----
    ");
    		display.append(dough + "
    ");
    		display.append(sauce + "
    ");
    		for (String topping : toppings) {
    			display.append(topping + "
    ");
    		}
    		return display.toString();
    	}
    }
    

    我们来定义一些具体的子类,在这里,其实就是定义纽约和芝加哥风味的芝士披萨

    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");
    	}
    }
    
    public class ChicagoStyleClamPizza extends Pizza {
    	public ChicagoStyleClamPizza() {
    		name = "Chicago Style Clam Pizza";
    		dough = "Extra Thick Crust Dough";
    		sauce = "Plum Tomato Sauce";
     
    		toppings.add("Shredded Mozzarella Cheese");
    		toppings.add("Frozen Clams from Chesapeake Bay");
    	}
     
    	void cut() {
    		System.out.println("Cutting the pizza into square slices");
    	}
    }
    

    好了等久了吧,马上来吃披萨了,这个时候刚好是下午4点左右,小编感觉已经饿的不行。

    public class PizzaTestDrive {
     
    	public static void main(String[] args) {
    		PizzaStore nyStore = new NYPizzaStore();
    		PizzaStore chicagoStore = new ChicagoPizzaStore();
     
    		Pizza pizza = nyStore.orderPizza("cheese");
    		System.out.println("Ethan ordered a " + pizza.getName() + "
    ");
     
    		pizza = chicagoStore.orderPizza("cheese");
    		System.out.println("Joel ordered a " + pizza.getName() + "
    ");
    
    		pizza = nyStore.orderPizza("clam");
    		System.out.println("Ethan ordered a " + pizza.getName() + "
    ");
     
    		pizza = chicagoStore.orderPizza("clam");
    		System.out.println("Joel ordered a " + pizza.getName() + "
    ");
    
    		pizza = nyStore.orderPizza("pepperoni");
    		System.out.println("Ethan ordered a " + pizza.getName() + "
    ");
     
    		pizza = chicagoStore.orderPizza("pepperoni");
    		System.out.println("Joel ordered a " + pizza.getName() + "
    ");
    
    		pizza = nyStore.orderPizza("veggie");
    		System.out.println("Ethan ordered a " + pizza.getName() + "
    ");
     
    		pizza = chicagoStore.orderPizza("veggie");
    		System.out.println("Joel ordered a " + pizza.getName() + "
    ");
    	}
    }
    

    好了,至此我们已经开了纽约和芝加哥披萨店,并已经愉快的制作和吃上了披萨,而且这是通过我们的工厂方法模式创建并得到的。

    关于认识工厂方法模式,因为这篇我们已经通过代码来了解了下,我将在下一篇进行解释并进一步认识这个模式,请大家敬请期待吧。

    PS:因为工厂模式涉及的篇幅较大,几篇文章可能存在不合理的衔接,小编会尽快输出全部文章,让大家能一次了解,在此给大家道个歉。

    GitHub地址 HeadFirstDesign

    爱生活,爱学习,爱感悟,爱挨踢

  • 相关阅读:
    [转载]ASP.NET Core 之 Identity 入门(一)
    ABP框架使用(版本3.3.1)
    [转载]ABP 结合 MongoDB 集成依赖注入
    [转载]初识ABP vNext(4):vue用户登录&菜单权限
    【转载】ASP.NET Core中如何显示[PII is hidden]的隐藏信息
    [转载]超简单本地mock假数据测试,模拟后台数据返回必杀技
    Git 分支简介、Git 和 GitHub 日常操作
    重载++运算符为成员函数(日期类函数设计也可以看一下 )
    重载操作符(cin cout 都在这篇文章里出现了 注意区别)
    重载操作符(日期类)
  • 原文地址:https://www.cnblogs.com/dimple91/p/10740506.html
Copyright © 2020-2023  润新知