什么时候在对象中使用工厂方法而不是factory类是一个好主意?
当前回答
如果你想在使用方面创建一个不同的对象。它很有用。
public class factoryMethodPattern {
static String planName = "COMMERCIALPLAN";
static int units = 3;
public static void main(String args[]) {
GetPlanFactory planFactory = new GetPlanFactory();
Plan p = planFactory.getPlan(planName);
System.out.print("Bill amount for " + planName + " of " + units
+ " units is: ");
p.getRate();
p.calculateBill(units);
}
}
abstract class Plan {
protected double rate;
abstract void getRate();
public void calculateBill(int units) {
System.out.println(units * rate);
}
}
class DomesticPlan extends Plan {
// @override
public void getRate() {
rate = 3.50;
}
}
class CommercialPlan extends Plan {
// @override
public void getRate() {
rate = 7.50;
}
}
class InstitutionalPlan extends Plan {
// @override
public void getRate() {
rate = 5.50;
}
}
class GetPlanFactory {
// use getPlan method to get object of type Plan
public Plan getPlan(String planType) {
if (planType == null) {
return null;
}
if (planType.equalsIgnoreCase("DOMESTICPLAN")) {
return new DomesticPlan();
} else if (planType.equalsIgnoreCase("COMMERCIALPLAN")) {
return new CommercialPlan();
} else if (planType.equalsIgnoreCase("INSTITUTIONALPLAN")) {
return new InstitutionalPlan();
}
return null;
}
}
其他回答
我认为这取决于你想要给你的代码带来的松耦合程度。
工厂方法解耦得很好,但是工厂类不行。
换句话说,使用工厂方法比使用简单的工厂(称为工厂类)更容易更改内容。
看看这个例子:https://connected2know.com/programming/java-factory-pattern/。现在,想象一下你想要带来一个新的动物。在Factory类中,您需要更改Factory,但在Factory方法中,不需要,您只需要添加一个新的子类。
这真的是个品味问题。工厂类可以根据需要进行抽象/接口,而工厂方法是轻量级的(而且往往是可测试的,因为它们没有定义的类型,但它们需要一个众所周知的注册点,类似于服务定位器,但用于定位工厂方法)。
我个人认为单独的Factory类有意义的一种情况是,当您试图创建的最终对象依赖于其他几个对象时。例如,在PHP中:假设你有一个House对象,它又有一个Kitchen和一个LivingRoom对象,LivingRoom对象内部也有一个TV对象。
实现这一点的最简单方法是让每个对象在它们的construct方法上创建它们的子对象,但是如果属性是相对嵌套的,那么当您的House创建失败时,您可能会花一些时间试图隔离到底是什么失败了。
另一种方法是做以下事情(依赖注入,如果你喜欢这个花哨的术语):
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
在这里,如果创建House的过程失败了,那么只有一个地方可以查看,但每次想要一个新House时都必须使用这个块,这非常不方便。进入工厂:
class HouseFactory {
public function create() {
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
return $HouseObj;
}
}
$houseFactory = new HouseFactory();
$HouseObj = $houseFactory->create();
由于这里的工厂,创建House的过程是抽象的(因为当您只想创建一个House时,您不需要创建和设置每个依赖项),同时是集中的,这使得它更容易维护。使用单独的工厂是有益的还有其他原因(例如可测试性),但我发现这个特定的用例最好地说明了工厂类是如何有用的。
考虑一个场景,当您必须设计Order和Customer类时。为了简单和初始需求,您不需要Order类的factory,并使用许多“new Order()”语句填充应用程序。一切都很顺利。
现在出现了一个新的需求,即Order对象不能在没有客户关联的情况下实例化(新的依赖项)。现在你有以下考虑。
1-你创建了只对新实现有效的构造函数重载。(不可接受)。 2-您更改Order()签名并更改每个调用。(这不是一个很好的练习,而且真的很痛苦)。
相反,如果你已经为Order Class创建了一个工厂,你只需要修改一行代码就可以了。我建议几乎所有聚合关联都使用Factory类。希望这能有所帮助。
我把工厂比作图书馆的概念。例如,您可以有一个库用于处理数字,另一个库用于处理形状。您可以将这些库的函数存储在逻辑上命名为Numbers或Shapes的目录中。这些是泛型类型,可以包括整数,浮点数,双元,长或矩形,圆形,三角形,在形状的情况下,五边形。
该系统采用了多态、依赖注入和控制反转等技术。
Factory Patterns的目的是:定义一个用于创建对象的接口,但是让子类来决定实例化哪个类。工厂方法允许类延迟实例化到子类。
假设你正在构建一个操作系统或框架,你正在构建所有的离散组件。
下面是PHP中工厂模式概念的一个简单示例。我可能不会完全理解,但这只是一个简单的例子。我不是专家。
class NumbersFactory {
public static function makeNumber( $type, $number ) {
$numObject = null;
$number = null;
switch( $type ) {
case 'float':
$numObject = new Float( $number );
break;
case 'integer':
$numObject = new Integer( $number );
break;
case 'short':
$numObject = new Short( $number );
break;
case 'double':
$numObject = new Double( $number );
break;
case 'long':
$numObject = new Long( $number );
break;
default:
$numObject = new Integer( $number );
break;
}
return $numObject;
}
}
/* Numbers interface */
abstract class Number {
protected $number;
public function __construct( $number ) {
$this->number = $number;
}
abstract public function add();
abstract public function subtract();
abstract public function multiply();
abstract public function divide();
}
/* Float Implementation */
class Float extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Integer Implementation */
class Integer extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Short Implementation */
class Short extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Double Implementation */
class Double extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Long Implementation */
class Long extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
$number = NumbersFactory::makeNumber( 'float', 12.5 );