前面分析了简单工厂模式和工厂方法模式,接着来看一下抽象工厂模式,他与工厂方法模式有一些相似的地方,也有不同的地方。

先来看一个不用工厂方法模式实现的订购披萨的代码:

对象依赖的问题:当你直接实例化一个对象时,就是在依赖他的具体类。接着上面的例子,如果在一个PizzaStore里面直接创建很多对象时,他们的依赖关系是这样的:

这里引出一个概念:依赖倒置。很清楚的代码里减少具体类的依赖是一件好事。依赖倒置的定义是:要依赖抽象,不要依赖实现。这个原则说说明了:不能让高层组建依赖底层组件,而且,不管是高层组件还是底层组件,他们都要依赖抽象。所谓的高层组件,是由其它底层组件定义其行为的类。例如。PizzaStore是个高层组件,因为他的行为是由比萨定义的:PizzaStore创建所有不同的比萨对象,准备、烘烤、切片、装盒;而披萨本身属于低层组件。

原则的应用

上图展示的问题在于,它依赖每个比萨类型,因为它是在自己的orderPizza方法中,实例化这些具体类型的。虽然我们已经创建了一个抽象,就是Pizza,但是我们仍然在代码中,实际的创建了具体的pizza,所以,这个抽象没有什么影响力。如何在OrderPizza方法中,将这些实例化对象的代码独立出来,我们都知道,工厂方法刚好能排上用场。所以,应用工厂方法之后。类图看起来就像这:

在应用了工厂方法模式之后(参考工厂方法模式),你将注意到,高层组件和底层组件都依赖了抽象(Pizza),要遵循依赖倒置原则,工厂方法并非唯一的技巧,但是,确实最有威力的技巧之一。

如何更好的遵循依赖倒置原则

变量不可以持有具体类的引用。如果使用new,就会持有具体类的引用,就会对具体的类产生依赖。可以改用工厂来避免这种做法。

不要让类派生自具体的类。如果派生自具体类,那你就会依赖具体类。请派生自一个抽象。

不要覆盖基类中已经实现的方法。基类中已实现的方法,应该由所有的子类共享。

上面三点只是说尽量去做到,并不是一定要做到。

抽象工厂模式

这个模式涉及的类有点儿多。。。所以决定线上UML类图,然后根据类图来一步一步的说明:

实际上单就拿抽象工厂来说,不是太难说明这个模式的含义,但是抽象工厂一般是和工厂方法模式配合使用的:

看图:首先,NYPizzaStore还是继承自PizzaStore

public abstract   class PizzaStore
{
public Pizza OrderPizza(string pizzaType)
{
Pizza pizza = CreatePizza(pizzaType);
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
public abstract Pizza CreatePizza(string pizzaType);
}

PizzaStroe依赖一个抽象的Pizza,而NYPizzaStore继承了PizzaStore,覆写了CreatePIzza:

 public class NyPizzaStore:PizzaStore
{
public override Pizza CreatePizza(string pizzaType)
{
Pizza pizza=null;
var indigredientFactory=new NyPizzaIngredientFactory();
if (pizzaType=="Cheese")
{
pizza = new CheesePizza(indigredientFactory);
}
else if (pizzaType=="Clam")
{
pizza=new ClamPizza(indigredientFactory);
}
return pizza;
}
}

实现的这个NYPizzaStore的耦合比较高,因为他在俩面new了三个对象:一个抽象工厂NyPizzaIngredientFactory,两个具体的披萨CheesePizza和ClamPizza。但是因为这个部分应该是不易变的部分,以后也不会进行修改了(如果不是这样的话那这个类还得继续抽象不是么?)此外,NYPizzaStore还针对一个Pizza抽象进行了编程,Pizza的代码如下:

public abstract class Pizza
{
public string Name { get; set; }
public Dough Dough { get; set; }
public Sauce Sauce { get; set; }
public Veggie[] Veggies { get; set; }
public Repperoni Repperoni { get; set; }
public Clams Clams { get; set; }
public Cheese Cheese { get; set; }
public abstract void Prepare(); public void Bake()
{
Console.WriteLine("bake...");
} public void Cut()
{
Console.WriteLine("Cut...");
} public void Box()
{
Console.WriteLine("Box...");
} public override string ToString()
{
return this.Name;
}
}

Pizza里面依赖了很多的抽象,也就是说Pizza是针对抽象在编程,具体是一个什么披萨,应该交给Pizza的子类来进行详细的描述,此外,看到Pizza里面还有一个抽象的Prepare方法,由此判断出来Pizza类也实现了工厂方法模式。看一下Pizza的具体实现类(其中一个):

 public class CheesePizza : Pizza
{
private IPizzaIngredientFactory _factory; public CheesePizza(IPizzaIngredientFactory factory)
{
_factory = factory;
}
public override void Prepare()
{
Console.WriteLine($"Preparing {Name}");
Dough = _factory.CreateDough();
Sauce = _factory.CreateSauce();
Cheese = _factory.CreateCheese();
}
}

CheesePizaa针对一个抽象的IPizzaIngredientFactory进行编程,这种利用组合的方式避免了继承带来的静态的编译所造成的不便,使得代码可以在运行时体现出更灵活和可扩展的特性。IPizzaIngredientFactory是一个抽象工厂的接口,抽象工厂又叫做原料工厂,就是说生产产品所需要的各种原料都可以从抽象工厂来获取:

 public class NyPizzaIngredientFactory : IPizzaIngredientFactory
{
public Dough CreateDough()
{
return new ThinCruseDough();
} public Sauce CreateSauce()
{
return new MarinaraSauce();
} public Cheese CreateCheese()
{
return new ReggianoChesse();
} public Veggie[] CreateVeggies()
{
return new Veggie[]
{
new Garlic(), new Mushroom(), new Onion(), new RedPepper(),
};
} public Repperoni CreateRepperoni()
{
return new SlicedRepperoni();
} public Clams CreateClams()
{
return new FreshClams();
}
}

下面给出抽象工厂的定义:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。在这个示例中,这个接口指的就是IPizzaInfredientFactory。

最重要的结论是,抽象工厂并不是单独使用的,而是在工厂方法模式中进行扩展使用的。有的时候,我们要创建一些相关联的或依赖的一族对象,这个时候可以把创建这些对象用抽象工厂来实现,而不是用工厂方法模式来实现,如果用工厂方法模式来实现,一个抽象产品对应一个抽象工厂,那样的情况叫做“类型爆炸”。

最最重要的是:工厂方法模式遵循控制反转的设计原则,并在此基础上定义了一个框架,在框架中,如果又必要的话,将抽象工厂的逻辑放到这个框架中的适当位置上。所以,工厂方法模式和抽象工厂模式一般是配合使用的。抽象工厂的作用就是防止"类型爆炸”。

要点:

所有工厂都是用来封装对象的创建。

简单工厂提供给我们更多的是一种想法,让我们萌生了将系统做一些分隔的想法,比如将对象的使用和实现进行解耦,等等。

工厂方法使用的是继承和多态,吧对象的创建委托给子类。

抽象工厂使用的是对象的组合。对象的创建被实现在工厂接口所暴露的方法中来,比如Pizza类就实现工厂方法模式,里面的Prepare就是一个工厂方法。

所有工厂模式都是通过减少应用程序和类之间的依赖促进耦合。

依赖倒置原则,指导我们要尽量避免依赖具体,而要依赖抽象。

工厂是很有威力的技巧,帮我们尽量针对接口编程,而不是针对具体。

C#设计模式之6:抽象工厂模式的更多相关文章

  1. 大话设计模式C++版——抽象工厂模式

    前面说过,简单工厂模式是最基础的一种设计模式,那以工厂命名的设计模式就是23种设计模式中最多的一种,他们一脉相承,一步一步进化而来,这里就是其中的最后一种——抽象工厂模式(Abstract Facto ...

  2. JAVA常用设计模式(一、抽象工厂模式)

    抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最 ...

  3. 设计模式学习心得<抽象工厂模式 Abstract Factory>

    抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 在抽 ...

  4. C#设计模式系列:抽象工厂模式(AbstractFactory)

    出自:http://www.cnblogs.com/libingql/archive/2012/12/09/2809754.html 1. 抽象工厂模式简介 1.1 定义 抽象工厂(Abstract ...

  5. [Python编程实战] 第一章 python的创建型设计模式1.1抽象工厂模式

    注:关乎对象的创建方式的设计模式就是“创建型设计模式”(creational design pattern) 1.1 抽象工厂模式 “抽象工厂模式”(Abstract Factory Pattern) ...

  6. IOS设计模式浅析之抽象工厂模式(Abstract Factory)

    概述 在前面两章中,分别介绍了简单工厂模式和工厂方法模式,我们知道简单工厂模式的优点是去除了客户端与具体产品的依赖,缺点是违反了“开放-关闭原则”:工厂方法模式克服了简单工厂模式的缺点,将产品的创建工 ...

  7. 大话设计模式Python实现- 抽象工厂模式

    抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的类 下面是一个抽象工厂的demo: #!/usr/bin/env pyth ...

  8. 【java设计模式】-03抽象工厂模式

    抽象工厂 简述 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类.在抽象工厂模式中,接口是负责创建一个相关对象的工厂 ...

  9. 一天一个设计模式——Abstract Factory抽象工厂模式

    一.模式说明 前面学习了工厂方法(Factory Method)模式.在工厂方法模式中,在工厂方法模式中,父类决定如何生成实例,但并不决定所要生成的具体类,具体的处理交由子类来处理.这里学习的抽象工厂 ...

  10. 重学 Java 设计模式:实战抽象工厂模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

随机推荐

  1. Lingo求解线性规划案例3——混料问题

    凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/  某糖果厂用原料A.B和C按不向比率混合加工而成甲.乙.丙三种糖果(假设混合加工中不损耗原料).原料A.B.C ...

  2. npm方法

    1. 使用npm 下载全局包 npm install 包名字 -g 安装 npm uninstall 包名字 -g 卸载 2. 安装卸载本地的包 (在哪里执行命令就把包安装在哪个目录的node_mod ...

  3. [Java] SpringMVC工作原理之二:HandlerMapping和HandlerAdapter

    一.HandlerMapping 作用是根据当前请求的找到对应的 Handler,并将 Handler(执行程序)与一堆 HandlerInterceptor(拦截器)封装到 HandlerExecu ...

  4. 2018年6月,最新php工程师面试总结

    面试经常被问到的问题总结 1.字符串函数 2.数组函数 3.cookie和session的区别 4.状态码以及其功能

  5. A1制作文件夹目录

    第一步 在文件夹目录下建立bat文件,填写以下内容: dir *.* /B >目录.txt 最后双击bat文件. 第二步 运行后复制目录.txt文件内容到空白excel 使用hyperlink函 ...

  6. w3m 在ubuntu中的使用

    w3m 使用总结 安装 sudo apt install w3m终端 w3m www.baidu.com 即可打开w3m是个开放源代码的命令行下面的网页浏览器.一般的linux系统都会自带这个工具,可 ...

  7. [POI2012]SZA-Cloakroom

    嘟嘟嘟 一道比较有意思的dp. 这题关键在于状态的设计.如果像我一样令\(dp[i][j]\)表示选到第\(i\)个物品,\(\sum c\)能都等于\(j\)的话,那就是\(O(qnk)\)了,怒拿 ...

  8. P2819 图的m着色问题(DFS)

    思路:最开始的回溯顺序是正常的图遍历的回溯顺序,其实也没有错.但是,因为怎么调都不对,看了题解.下面,请结合题解思路和代码一起感受一下回溯顺序的改变,算法的改变和代码在哪里实现了这种顺序. 回溯顺序: ...

  9. Python:Day04

    数学运算符: +  加 -  减 *  乘 **  指数运算 /  除 //  整除 %  取余 比较运算符: >  大于 <  小于 >=  大于等于 <=  小于等于 == ...

  10. (二 -4) 天猫精灵接入Home Assistant-自动发现Mqtt设备--传感器系列

    https://www.home-assistant.io/blog/2015/10/11/measure-temperature-with-esp8266-and-report-to-mqtt/ 最 ...