- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在整理这个设计模式的解释和代码示例,试图帮助我周围的人掌握它(同时帮助我自己掌握这个模式)。
我正在寻找的是对我的解释和代码示例的意见或批评...谢谢!
什么是工厂模式?工厂模式利用一个特定的专用“对象创建者对象”来处理对象的创建和大多数情况下的实例化,类似于现实世界的工厂。
现实世界的例子
将汽车工厂想象成各种类型汽车的制造商。该汽车厂的一条装配线可能有一天会生产一辆卡车,但在另一天可能会重新装配以生产汽车。假设一家经销商向其指定的客户处理部门下了 10 辆汽车的订单。该部门然后利用某个工厂并订购了 10 辆汽车。客户经理不关心自己制造汽车(想象一下糟糕的结果)他们只处理最终产品,确保经销商得到他们的车辆。
同款汽车的一款新车型在明年问世,订单开始涌入。客户处理人员(仍然不关心汽车的生产)下了订单,但现在他们收到的汽车不同了,组装方法甚至工厂可能完全不同,但帐户处理程序不必担心这一点。另一个想法:如果某个客户处理程序下订单,车辆的工厂组装商可能确切地知道要采取什么行动(即客户处理程序 X 下订单,工厂组装商知道对于客户处理程序 X,他们生产 10 辆 Y 型车辆).另一种选择可能是客户经理告诉装配商要生产什么类型的车辆。
如果帐户处理程序也处理车辆的创建(即它们是耦合的),则每次车辆以任何方式发生变化时,每个帐户处理程序都必须接受再培训以生产该车辆。这会造成质量问题,因为客户处理人员的数量远远多于工厂的数量……会发生错误,费用也会高得多。
回到 OOP
对象工厂作为一种应用于软件工程的设计模式在概念上类似于上面的例子......某种方式。汇编器可以检查请求的客户端和句柄,或者客户端可以告诉汇编器它需要什么对象。现在......你在一个项目中创建了一个对象工厂和各种装配器,在项目的后期,需求略有变化,你现在被要求改变对象内容以及它的客户如何处理该对象。由于您使用了工厂模式,因此这是一个简单的更改,并且在一个位置,您可以更改或添加工厂生成的对象,并更改汇编器布置对象内容的格式。
完成此操作的不幸方法是没有工厂方法,在客户端中实例化每个对象实例并格式化对象内容……假设您在 20 个客户端中使用了这个特定对象。现在你必须去每个客户端,改变每个对象实例和格式......多么浪费时间......偷懒......第一次就以正确的方式做,这样你就可以节省自己(和其他人)的时间和以后的努力。
代码示例 (C#)
下面是一个利用工厂生产食品和各种食品的例子
Factory module
public enum FoodType
{
//enumerated foodtype value, if client wants to specify type of object, coupling still occurs
Hamburger, Pizza, HotDog
}
/// <summary>
/// Object to be overridden (logical)
/// </summary>
public abstract class Food
{
public abstract double FoodPrice { get; }
}
/// <summary>
/// Factory object to be overridden (logical)
/// </summary>
public abstract class FoodFactory
{
public abstract Food CreateFood(FoodType type);
}
//-------------------------------------------------------------------------
#region various food objects
class Hamburger : Food
{
double _foodPrice = 3.59;
public override double FoodPrice
{
get { return _foodPrice; }
}
}
class Pizza : Food
{
double _foodPrice = 2.49;
public override double FoodPrice
{
get { return _foodPrice; }
}
}
class HotDog : Food
{
double _foodPrice = 1.49;
public override double FoodPrice
{
get { return _foodPrice; }
}
}
#endregion
//--------------------------------------------------------------------------
/// <summary>
/// Physical factory
/// </summary>
public class ConcreteFoodFactory : FoodFactory
{
public override Food CreateFood(FoodType foodType)
{
switch (foodType)
{
case FoodType.Hamburger:
return new Hamburger();
break;
case FoodType.HotDog:
return new HotDog();
break;
case FoodType.Pizza:
return new Pizza();
break;
default:
return null;
break;
}
}
}
/// <summary>
/// Assemblers
/// </summary>
public class FoodAssembler
{
public string AssembleFoodAsString(object sender, FoodFactory factory)
{
Food food = factory.CreateFood(FoodType.Hamburger);
if (sender.GetType().Name == "default_aspx")
{
return string.Format("The price for the hamburger is: ${0}", food.FoodPrice.ToString());
}
else
{
return food.FoodPrice.ToString();
}
}
public Food AssembleFoodObject(FoodFactory factory)
{
Food food = factory.CreateFood(FoodType.Hamburger);
return food;
}
}
Calling factory
FoodFactory factory = new ConcreteFoodFactory(); //create an instance of the factoryenter code here
lblUser.Text = new FoodAssembler().AssembleFoodAsString(this, factory); //call the assembler which formats for string output
Object o = new FoodAssembler().AssembleFoodObject(factory); //example: instantiating anon object, initialized with created food object
最佳答案
对不起。那是一个相当不灵活的工厂。反射(reflection)可以给一些 POWWAH!!
public interface IFood
{
bool IsTasty { get; }
}
public class Hamburger : IFood
{
public bool IsTasty {get{ return true;}}
}
public class PeaSoup : IFood
{
public bool IsTasty { get { return false; } }
}
public class FoodFactory
{
private Dictionary<string, Type> _foundFoodTypes =
new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Scan all specified assemblies after food.
/// </summary>
public void ScanForFood(params Assembly[] assemblies)
{
var foodType = typeof (IFood);
foreach (var assembly in assemblies)
{
foreach (var type in assembly.GetTypes())
{
if (!foodType.IsAssignableFrom(type) || type.IsAbstract || type.IsInterface)
continue;
_foundFoodTypes.Add(type.Name, type);
}
}
}
/// <summary>
/// Create some food!
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public IFood Create(string name)
{
Type type;
if (!_foundFoodTypes.TryGetValue(name, out type))
throw new ArgumentException("Failed to find food named '" + name + "'.");
return (IFood)Activator.CreateInstance(type);
}
}
用法:
var factory = new FoodFactory();
factory.ScanForFood(Assembly.GetExecutingAssembly());
Console.WriteLine("Is a hamburger tasty? " + factory.Create("Hamburger").IsTasty);
编辑、反馈您的代码:
首先,工厂用于在添加新类型的实现时能够创建尽可能少的代码更改的对象。使用枚举意味着所有调用工厂的地方都需要使用枚举并在枚举更改时更新。
当然,它仍然比直接创建类型要好一些。
您的代码的第二个问题是您使用的是 switch 语句(但如果需要枚举,这是最好的方法)。最好能够以某种方式注册所有不同的类。从配置文件或允许实际实现(例如 Hamburger 类)自行注册。这就要求工厂遵循单例模式。
Reflection 来拯救你了。反射允许您遍历 DLL 和 EXE 中的所有类型。所以我们可以搜索所有实现我们接口(interface)的类,因此能够为所有类构建一个字典。
关于c# - 工厂设计模式(需要批判),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4099969/
对此感到疯狂,真的缺少一些东西。 我有webpack 4.6.0,webpack-cli ^ 2.1.2,所以是最新的。 在文档(https://webpack.js.org/concepts/mod
object Host "os.google.com" { import "windows" address = "linux.google.com" groups = ["linux"] } obj
每当我安装我的应用程序时,我都可以将数据库从 Assets 文件夹复制到 /data/data/packagename/databases/ .到此为止,应用程序工作得很好。 但 10 或 15 秒后
我在 cc 模式缓冲区中使用 hideshow.el 来折叠我不查看的文件部分。 如果能够在 XML 文档中做到这一点就好了。我使用 emacs 22.2.1 和内置的 sgml-mode 进行 xm
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
根据java: public Scanner useDelimiter(String pattern) Sets this scanner's delimiting pattern to a patt
我读过一些关于 PRG 模式以及它如何防止用户重新提交表单的文章。比如this post有一张不错的图: 我能理解为什么在收到 2xx 后用户刷新页面时不会发生表单提交。但我仍然想知道: (1) 如果
看看下面的图片,您可能会清楚地看到这一点。 那么如何在带有其他一些 View 的简单屏幕中实现没有任何弹出/对话框/模式的微调器日期选择器? 我在整个网络上进行了谷歌搜索,但没有找到与之相关的任何合适
我不知道该怎么做,我一直遇到问题。 以下是代码: rows = int(input()) for i in range(1,rows): for j in range(1,i+1):
我想为重写创建一个正则表达式。 将所有请求重写为 index.php(不需要匹配),它不是以/api 开头,或者不是以('.html',或'.js'或'.css'或'.png'结束) 我的例子还是这样
MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式 MVC模式用于应用程序的分层开发 Model(模型) - 模型代表一个存取数据的对象或 JAVA PO
我想为组织模式创建一个 RDF 模式世界。您可能知道,组织模式文档基于层次结构大纲,其中标题是主要的分组实体。 * March auxiliary :PROPERTIES: :HLEVEL: 1 :E
我正在编写一个可以从文件中读取 JSON 数据的软件。该文件包含“person”——一个值为对象数组的对象。我打算使用 JSON 模式验证库来验证内容,而不是自己编写代码。符合代表以下数据的 JSON
假设我有 4 张 table 人 公司 团体 和 账单 现在bills/persons和bills/companys和bills/groups之间是多对多的关系。 我看到了 4 种可能的 sql 模式
假设您有这样的文档: doc1: id:1 text: ... references: Journal1, 2013, pag 123 references: Journal2, 2014,
我有这个架构。它检查评论,目前工作正常。 var schema = { id: '', type: 'object', additionalProperties: false, pro
这可能很简单,但有人可以解释为什么以下模式匹配不明智吗?它说其他规则,例如1, 0, _ 永远不会匹配。 let matchTest(n : int) = let ran = new Rand
我有以下选择序列作为 XML 模式的一部分。理想情况下,我想要一个序列: 来自 my:namespace 的元素必须严格解析。 来自任何其他命名空间的元素,不包括 ##targetNamespace和
我希望编写一个 json 模式来涵盖这个(简化的)示例 { "errorMessage": "", "nbRunningQueries": 0, "isError": Fals
首先,我是 f# 的新手,所以也许答案很明显,但我没有看到。所以我有一些带有 id 和值的元组。我知道我正在寻找的 id,我想从我传入的三个元组中选择正确的元组。我打算用两个 match 语句来做到这
我是一名优秀的程序员,十分优秀!