我无法理解为工厂类定义抽象类/接口的作用,这是我在Web上的所有教程中总能看到的。有人可以说一下CreatorInterface的重要性吗? Reference UML Diagram of the Factory Pattern
要输入代码形式,这就是我所拥有的:
代码示例1
// Product
public abstract class Vehicle
{
public string VehicleType { get; set; }
}
// Concrete Product
public class Bike : Vehicle
{
public Bike()
{
VehicleType = "Two Wheeler";
}
}
// Concrete Product
public class Car : Vehicle
{
public Car()
{
VehicleType = "Four Wheeler";
}
}
// Concrete Factory
public class VehicleFactory
{
public Vehicle GetVehicle(string VehicleType)
{
if (VehicleType == "Bike")
return new Bike();
else if (VehicleType == "Car")
return new Car();
else
return null;
}
}
// Client class
public class ClientClass
{
public void Main()
{
VehicleFactory VehicleFactoryObj = new VehicleFactory();
Vehicle BikeObj = VehicleFactoryObj.GetVehicle("Bike");
Vehicle CarObj = VehicleFactoryObj.GetVehicle("Car");
}
}
上面的代码不包含'VehicleFactory'类的任何抽象类。但它运作正常。现在,为“VehicleFactory”添加抽象类的原因是什么?在我看来,添加一个抽象类对于抽象工厂方法是有意义的。 [如果我错了,请纠正我]
GoF的定义:
定义用于创建对象的接口,但让子类决定 要实例化的类。 Factory方法允许类延迟 它用于子类的实例化。
据我所知,模式背后的核心问题是你想要创建不同类的实例,而不是将创建逻辑暴露给消费者。 如果我在这里弄错了,请告诉我。我在这里也有点困惑,因为我在网上看到的例子。例如,在Wiki上,Php和C#示例。我可以在C#示例中消化模式的要求,但不能在PHP示例中消化。无论如何,以下陈述将帮助您清楚地理解我的问题。
例如,我们的图书馆有两个车辆类Bike和Car,它们都有车型号。 Bike型号以“BK”开头,车型号以“CR”开头。现在,我们希望根据Vehicle Model Number返回任一类的实例,而不将逻辑暴露给客户端。 [注意这是一个更新的场景,我提出,因为前面的一个决定了这个类的逻辑很弱,并且对使用字符串产生了混淆]
因此我们可以创建一个车辆工厂类,它公开一个返回相应车辆实例的静态方法。
如果客户端知道选择逻辑,那么我可能不需要模式本身。所以,可能看起来像:
代码示例2
// Product
public abstract class Vehicle
{
public int NumberOfWheels { get; set; }
}
// Concrete Product
public class Bike : Vehicle
{
public Bike()
{
NumberOfWheels = 2;
}
}
// Concrete Product
public class Car : Vehicle
{
public Car()
{
NumberOfWheels = 4;
}
}
// Client class
public class ClientClass
{
public void Main()
{
String ModelNumber = "BK-125";
Vehicle CurrentVehicle;
if (ModelNumber.Contains("BK"))
{
CurrentVehicle = new Bike();
}
else if(ModelNumber.Contains("CR"))
{
CurrentVehicle = new Car();
}
}
}
工厂模式让我只需通过创建工厂来隐藏客户端的创建逻辑。因此,客户端现在只需要调用Factory的create方法,并且他将获得适当的类实例作为回报。现在代码看起来像。
代码示例3
// Product
public abstract class Vehicle
{
public int NumberOfWheels { get; set; }
}
// Concrete Product
public class Bike : Vehicle
{
public Bike()
{
NumberOfWheels = 2;
}
}
// Concrete Product
public class Car : Vehicle
{
public Car()
{
NumberOfWheels = 4;
}
}
// Concrete Factory
public class VehicleFactory
{
public Vehicle GetVehicle(string ModelNumber)
{
if (ModelNumber.Contains("BK"))
return new Bike();
else if (ModelNumber.Contains("CR"))
return new Car();
else
return null;
}
}
// Client class
public class ClientClass
{
public void Main()
{
VehicleFactory VehicleFactoryObj = new VehicleFactory();
Vehicle BikeObj = VehicleFactoryObj.GetVehicle("BK-125");
Vehicle CarObj = VehicleFactoryObj.GetVehicle("CR-394");
}
}
现在问题来自抽象工厂类
添加抽象工厂类的一个好处是,我从讨论中了解到,客户端将能够覆盖'GetVehicle'方法来覆盖逻辑。对于他可能创造了更多车辆类别的情况,例如“卡车”。但即使在这种情况下,如果他想要覆盖所有三种工厂方法,即自行车,汽车和卡车,他将不会有他的整个逻辑,因为自行车和汽车创建的逻辑是用Factory方法编写的。虽然他将能够为他所有的新车型创造新的逻辑。有人可以对此有所了解吗?
我更想指出的是这个问题是关于工厂模式,我明白抽象工厂模式将需要一个抽象工厂,因为在抽象工厂模式中我们正在创建工厂工厂< / strong>即可。但是在Factory模式中我们只有一个对象工厂,那为什么我们需要工厂的接口呢?
提前致谢!! : - )
答案 0 :(得分:0)
是的,它有效,但它并不理想。 VehicleFactory
有一个非常通用的方法,一旦你添加更多的车辆,将会很痛苦,因为你需要一个非常长的方法来检查所有的字符串。
想象一下,你有十五辆车。然后,您需要一个非常长的方法来枚举所有选项并生成正确的汽车。这都是不必要的慢,并且容易出错,因为你很容易错过/删除它,并且调试起来会非常困难。一般来说长方法都有不良的代码味道。
除了之外,每次添加继承VehicleFactory
的内容时都需要编辑Vehicle
类。但是如果您的图书馆用户没有这样做,会发生什么?可以访问它但想继承车辆吗?但是,通过定义一个抽象的VehicleFactory
类,他可以从中继承并定义自己的工厂方法。
简而言之,抽象工厂方法只会使您的代码更容易扩展。
同时生成依赖于字符串的车辆是一个非常糟糕的主意;如果使用大写或拼写错误怎么办?它除此之外还很慢。最好有这样的东西。
public abstract class VehicleFactory
{
public abstract Vehicle GetVehicle(string VehicleType)
}
public class CarFactory : VehicleFactory
{
public override Vehicle GetVehicle(string VehicleType)
{
return new Car();
}
}
public class BikeFactory : VehicleFactory
{
public override Vehicle GetVehicle(string VehicleType)
{
return new Bike();
}
}
public class ClientClass
{
public void Main()
{
//Create Factories
BikeFactory BikeFactoryObj = new BikeFactory();
CarFactory CarFactoryObj = new CarFactory();
//create Vehicles from factories. If wanted they can be casted to the inherited type.
Vehicle VehicleObj=BikeFactoryObj.GetNewVehicle();
Bike BikeObj = (Bike)BikeFactoryObj.GetVehicle();
Car CarObj = (Car)CarFactoryObj.GetVehicle();
//They are all inherited from Vehicle so can be used in a list of Vehicles
List<Vehicle> Vehicles=new List<Vehicle>()
{
VehicleObj,
BikeObj,
CarObj
}
}
}
此处出现错误的机会要少得多,而且这可以轻松地由班级中的任何用户进行缩放。
答案 1 :(得分:0)
简单来说,您的基类应该是抽象的,取决于您是否希望能够声明一个新类。
如果你想阻止开发者(或你自己)前往:
var myVehicle = new Vehicle();
而是强制所有车辆应该是从车辆继承的孩子,然后你宣布它是抽象的。
然后,当他们尝试执行上述代码时,会出现编译错误,导致他们无法声明新的抽象类。
如果用户可以声明新的基类,那么基类非抽象没有错。
答案 2 :(得分:0)
@Yair Halberstadt“......为什么我更喜欢Factory工厂方法而不是静态工厂...”。两者都有不同的用途。静态工厂是一个代码块,它(只)收集对象层次结构的实例化代码(很容易让人相信这个名称)。但它的本质是静态的(尽管可以在实例级别编写),这意味着它在编译时受到限制。当然我们可以扩展静态工厂,但主要是作为补丁代码。 (在框架级别主要不优选客户端扩展。)
相比之下,Factory方法对于编写通用业务逻辑非常有用,无需指定客户将在以后日期编写的具体受益人类型。
一个虚构的例子(假设普遍的税收计算) -
public abstract class TaxComputer {
protected abstract Calculator getCalculator();// Factory method
public void registerIncome(){
//...
}
public Amount computeTax(){
Calculator alculator = getCalculator();
//... Tax computation logic using abstract Calculator
// Note: Real Calculator logic has not been written yet
return tax;
}
}
public interface Calculator {
Amount add(Amount a, Amount b);
Amount subtract(Amount a, Amount b);
Amount multiply(Amount a, double b);
Amount roundoff(int nearestAmount);
// ...
}
我的所有Tax规则实现都是指使用 Amount 进行操作的抽象计算器。它目前只需要抽象计算器。 Tax计算机准备就绪后,可以发布它以供客户端扩展(扩展点为抽象类和钩子工厂方法)。
特定客户可以将其扩展到Yen(没有小数点)或Dollar / Pound等的计算,甚至可以根据当地规则在每次操作后将计算器(例如下一个10卢比)四舍五入。
相同的方式USDollarTaxCalculator将使用自己的操作规则扩展它(但不能也不需要重新定义Tax规则)
public class YenTaxComputer extends TaxComputer {
@Override
protected Calculator getCalculator() {
return new YenCalculator();
}
}
public class YenCalculator implements Calculator {
@Override
public Amount add(Amount a, Amount b) {
/*Yen specific additions and rounding off*/
}
@Override
public Amount subtract(Amount a, Amount b) {/*...*/ }
@Override
public Amount multiply(Amount a, double b) {/*...*/ }
@Override
public Amount roundoff(int nearestAmount) {/*...*/ }
}
在工厂方法点不是关于隐藏创建逻辑,而是为客户端保留扩展。
客户端看起来像
public class TaxClient {
public static void main(String[] args) {
TaxComputer computer = new YenTaxComputer();//
computeTax(computer);
}
/** A PLACE HOLDER METHOD FOR DEMO
*/
private static void computeTax(TaxComputer computer) {
Amount tax = computer.computeTax();
Amount Payment = ...
//...
}
}
这里需要注意的要点
答案 3 :(得分:0)
我发现以下链接非常有助于理解为Factory提供抽象类的逻辑,以及使用Factory Pattern本身的逻辑。
https://msdn.microsoft.com/en-us/library/ee817667.aspx
让我引用文章背后的逻辑
考虑一个为各种个人计算机的装配建模的应用程序。该应用程序包含一个负责组装计算机的 ComputerAssembler 类,一个为正在构建的计算机建模的计算机类,以及一个 ComputerFactory 创建Computer类实例的类。在使用工厂模式时, ComputerAssembler 类将创建计算机实例的责任委派给 ComputerFactory 。这确保了如果实例化和/或初始化过程发生变化(例如,新构造函数,激活器的使用,自定义池等), ComputerAssembler 根本不需要改变。这是从使用中抽象对象的创建的好处。
此外,假设业务需求发生变化,需要组装新型计算机。可以修改 ComputerFactory 类来创建新计算机类的实例(假设此新类具有与计算机相同的接口),而不是直接修改 ComputerAssembler 类。此外,还可以通过创建一个新工厂类(与 ComputerFactory 具有相同的接口)来创建新计算机类的实例(同样具有与计算机强>)。和以前一样, ComputerAssembler 类中的任何内容都不需要更改,所有逻辑都会像以前一样继续工作。这是将产品和工厂的类型抽象为不变接口的好处。
第二段指出,创造者使我们能够创建新工厂,处理产品中可能引入的变化,或者创建它们的逻辑,迫使我们创建新工厂。