我正在整理这个设计模式的解释和代码示例,试图帮助我周围的人掌握它(同时也帮助我自己掌握这个模式)。
我正在寻找的是意见&或批评我的解释和代码sample...thanks!
工厂的模式是什么?工厂模式使用特定的专用“对象创建者对象”来处理对象的创建(大多数情况下是实例化),类似于一个真实的工厂。
真实世界示例
想象一家汽车厂是各种类型汽车的创造者。那家汽车厂的一条装配线可以某一天生产一辆卡车,但在另一天可以重新生产汽车。比如说,一家经销商向他们指定的账户处理部门订购了10辆汽车。然后,该部门利用某一工厂,订购了10辆汽车。帐户处理程序不关心汽车本身(想象糟糕的结果),他们只使用最终产品,以确保经销商获得他们的车辆。
第二年,同一辆车的新型号问世,订单开始源源不断。帐户处理程序(仍然不关心汽车的生产)下订单,但现在他们收到的汽车是不同的,装配方法,甚至工厂可能完全不同,但帐户处理程序不必担心这一点。另一个想法是:如果某个帐户处理程序下了订单,车辆的工厂汇编程序可能确切地知道该采取什么行动(例如,帐户处理程序X下订单,工厂汇编程序知道对于帐户处理程序X,它们生产10辆Y型车辆)。另一种选择可能是帐户处理程序告诉汇编程序具体要生产哪种类型的车辆。
如果帐户处理程序也处理车辆的创建(即它们是耦合的),那么每次车辆以任何方式改变时,每个帐户处理程序都必须在生产该车辆方面接受再培训。这将产生质量问题,因为有更多的帐户处理程序将发生比factories...mistakes会发生,费用将更大。
返回OOP
对象工厂作为应用于软件工程的设计模式类似于概念…中的上述示例。工厂生产各种类型的其他对象,您可以使用一条流水线( objects ),它生成某种对象类型,并以某种方式返回。汇编程序可以检查请求的客户端和句柄,或者客户端可以告诉汇编程序它需要什么对象。Now...you在一个项目上创建一个对象工厂和各种汇编程序,稍后在项目中,需求略有变化,您现在被要求更改对象内容及其客户端处理该对象的方式。由于您使用了工厂模式--这是一个简单的更改,并且在一个位置上,您可以更改或添加工厂生成的对象,并更改汇编程序放置对象内容的格式。
这样做的不幸方法是没有工厂方法,实例化每个对象实例并格式化客户机themselves...say中的对象内容,您在20个客户端中使用了这个特定对象。现在您必须访问每个客户端,修改每个对象实例,并formats...what浪费时间--…第一次要以正确的方式进行lazy...do,这样以后您就节省了自己(和其他人)的时间和精力。
代码示例(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发布于 2010-11-04 18:49:25
抱歉的。那是一家相当不灵活的工厂。反射能给你一些好处!!
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);编辑,反馈您的代码:
首先,在添加新类型的实现时,工厂通常能够创建具有少量代码更改的对象。使用枚举意味着调用工厂的所有位置都需要使用枚举,并在枚举更改时进行更新。
当然,它仍然比直接创建类型要好一些。
代码的第二个问题是,您使用的是开关语句(但如果枚举是必需的,这是最好的方法)。最好能以某种方式注册所有不同的类。无论是从配置文件还是通过允许实际实现(例如,汉堡类)注册自己。这要求工厂遵循单例模式。
救援的倒影来了。反射允许您遍历DLL和EXE中的所有类型。因此,我们可以搜索实现我们接口的所有类,因此能够构建一个字典,所有类都可以。
发布于 2010-11-04 18:43:47
我认为你的解释,包括现实世界的例子是好的。但是,我不认为您的示例代码显示了该模式的真正好处。
一些可能的变化:
,
发布于 2010-11-04 18:38:36
我建议您使用接口而不是抽象类/继承。除此之外,它看起来还可以。
https://stackoverflow.com/questions/4099969
复制相似问题