工厂方法模式 - 这种模式有什么必要?
Factory Method pattern - what for this pattern is necessary?
我有摘要 class-factory Factory
与 factory-method getProduct()
和他的 child 类.
我有摘要class-productProduct
和他的child类.
Classes-factories 创建了 objects 个 classes-products。
abstract class Factory {
abstract function getProduct();
}
class FirstFactory extends Factory {
public function getProduct() {
return new FirstProduct();
}
}
abstract class Product {
};
class FirstProduct extends Product {
}
结果我可以使用这个客户端代码:
$factory = new FirstFactory();
$firstProduct = $factory->getProduct();
$factory = new SecondFactory();
$secondProduct = $factory->getProduct();
提问:这个模式需要什么?因为在客户端代码中我可以直接使用 类:
$firstProduct = new FirstProduct();
$secondProduct = new SecondProduct();
如果您在编译时知道 firstProduct
总是 FirstProduct
类型并且 secondProduct
总是 SecondProduct
类型那么就不需要工厂方法.
工厂方法仅在您想要创建可能 FirstProduct
或 SecondProduct
的产品时才有用,具体取决于工厂的运行时类型。例如,工厂的类型可能由用户输入决定。
可以注入工厂而不是实际的 class。假设您有一个 class 只能根据某些特定条件在运行时实例化,在这种情况下您不能执行 new Foo(...args) 。
一种选择是注入 FooFactory 并让它为您创建 Foo 实例。
重要的是要注意工厂模式并不总是最好的解决方案,对于简单的情况,使用简单的 new
会更好。例如,如果没有 Factory,您的示例可能会更好。
当您不需要在 class 的确切实现上工作但停留在 'abstraction layer'(例如接口和抽象 classes)时,工厂模式会发挥其全部作用。你可以看看"Dependency Inversion Principle DIP"(依赖于抽象。不要依赖于具体的classes)。
工厂用例:s一行数据库
例如,假设您有一个使用数据库系统的软件。无论出于何种原因,您知道所使用的具体数据库(MongoDB、SQL...)稍后可能会更改。 (或者甚至在开发过程中只需要文件中的假硬编码数据库)。工厂模式允许您通过调用正确的工厂在一行中从一个到另一个 s,因为所有的实现都依赖于抽象。 (这实际上是充分利用工厂模式的DAO模式,更多信息请参阅oracle文档:http://www.oracle.com/technetwork/java/dataaccessobject-138824.html)
具体示例:有 2 个派系的游戏
这是一个具体而简单的实现示例。
您有 2 个单位
- 苦工
- 战士
你有 2 个派系
- 兽人
- 兽人苦工
- 兽人战士
- 人类
- 人类苦工
- 人类战士
2 名玩家
- 兽人玩家(仅使用兽人单位)
- 人类玩家(仅使用人类单位)
您想实例化两个播放器,但具体播放器 class 应该以更通用的方式实现,以便以后可以重用。这在添加几个新派系的情况下也非常重要,您不想花时间回到您的玩家 class。
代码示例
要构建并 运行 它,请复制 Main.java,然后 javac Main.java
和 java Main
结果应该是
// Factories ----------------------------------------
abstract class AbsUnitFactory {
public abstract Warrior creaWarrior();
public abstract Peon creaPeon();
}
class OrcFactory extends AbsUnitFactory {
public Warrior creaWarrior() {
return new OrcWarrior();
}
public Peon creaPeon() {
return new OrcPeon();
}
}
class HumanFactory extends AbsUnitFactory {
public Warrior creaWarrior() {
return new HumanWarrior();
}
public Peon creaPeon() {
return new HumanPeon();
}
}
abstract class Unit {
public abstract String getRole();
public abstract String getFaction();
@Override
public String toString() {
String str = new String();
str += "[UNIT]\n";
str += " Role: " + this.getRole() + "\n";
str += " Faction: " + this.getFaction() + "\n";
return str;
}
}
// Warrior Units ----------------------------------------
abstract class Warrior extends Unit {
@Override
public String getRole() {
return "I'm a badass Warrior with the biggest sword!";
}
}
class OrcWarrior extends Warrior {
@Override
public String getFaction() {
return "Orc";
}
}
class HumanWarrior extends Warrior {
@Override
public String getFaction() {
return "Human";
}
}
// Peon Units ----------------------------------------
abstract class Peon extends Unit {
@Override
public String getRole() {
return "I'm a little simple peon... Ready to work.";
}
}
class HumanPeon extends Peon {
@Override
public String getFaction() {
return "Human";
}
}
class OrcPeon extends Peon {
@Override
public String getFaction() {
return "Orc";
}
}
// Main components ----------------------------------------
class Player {
private AbsUnitFactory factory;
private Peon myPeon;
private Warrior myWarrior;
public Player(AbsUnitFactory pFactory) {
this.factory = pFactory;
this.myPeon = this.factory.creaPeon();
this.myWarrior = this.factory.creaWarrior();
}
@Override
public String toString() {
return this.myPeon.toString() + this.myWarrior.toString();
}
}
class Main {
public static void main(String[] args) {
AbsUnitFactory humanFactory = new HumanFactory();
AbsUnitFactory orcFactory = new OrcFactory();
Player humanPlayer = new Player(humanFactory);
Player orcPlayer = new Player(orcFactory);
System.out.println("***** Human player *****");
System.out.println(humanPlayer.toString());
System.out.println("***** Orce player *****");
System.out.println(orcPlayer.toString());
}
}
查看玩家 class 如何被任何派系重复使用,唯一定义 派系使用的行是工厂。 (您甚至可以添加一个单例)。
更多资源
这些是我非常欣赏的书(关于设计模式)
- Head first 设计模式(http://shop.oreilly.com/product/9780596007126.do)
- 设计模式,可重用对象的元素(https://www.barnesandnoble.com/w/design-patterns-erich-gamma/1100886879)
我有摘要 class-factory Factory
与 factory-method getProduct()
和他的 child 类.
我有摘要class-productProduct
和他的child类.
Classes-factories 创建了 objects 个 classes-products。
abstract class Factory {
abstract function getProduct();
}
class FirstFactory extends Factory {
public function getProduct() {
return new FirstProduct();
}
}
abstract class Product {
};
class FirstProduct extends Product {
}
结果我可以使用这个客户端代码:
$factory = new FirstFactory();
$firstProduct = $factory->getProduct();
$factory = new SecondFactory();
$secondProduct = $factory->getProduct();
提问:这个模式需要什么?因为在客户端代码中我可以直接使用 类:
$firstProduct = new FirstProduct();
$secondProduct = new SecondProduct();
如果您在编译时知道 firstProduct
总是 FirstProduct
类型并且 secondProduct
总是 SecondProduct
类型那么就不需要工厂方法.
工厂方法仅在您想要创建可能 FirstProduct
或 SecondProduct
的产品时才有用,具体取决于工厂的运行时类型。例如,工厂的类型可能由用户输入决定。
可以注入工厂而不是实际的 class。假设您有一个 class 只能根据某些特定条件在运行时实例化,在这种情况下您不能执行 new Foo(...args) 。 一种选择是注入 FooFactory 并让它为您创建 Foo 实例。
重要的是要注意工厂模式并不总是最好的解决方案,对于简单的情况,使用简单的 new
会更好。例如,如果没有 Factory,您的示例可能会更好。
当您不需要在 class 的确切实现上工作但停留在 'abstraction layer'(例如接口和抽象 classes)时,工厂模式会发挥其全部作用。你可以看看"Dependency Inversion Principle DIP"(依赖于抽象。不要依赖于具体的classes)。
工厂用例:s一行数据库
例如,假设您有一个使用数据库系统的软件。无论出于何种原因,您知道所使用的具体数据库(MongoDB、SQL...)稍后可能会更改。 (或者甚至在开发过程中只需要文件中的假硬编码数据库)。工厂模式允许您通过调用正确的工厂在一行中从一个到另一个 s,因为所有的实现都依赖于抽象。 (这实际上是充分利用工厂模式的DAO模式,更多信息请参阅oracle文档:http://www.oracle.com/technetwork/java/dataaccessobject-138824.html)
具体示例:有 2 个派系的游戏
这是一个具体而简单的实现示例。
您有 2 个单位
- 苦工
- 战士
你有 2 个派系
- 兽人
- 兽人苦工
- 兽人战士
- 人类
- 人类苦工
- 人类战士
2 名玩家
- 兽人玩家(仅使用兽人单位)
- 人类玩家(仅使用人类单位)
您想实例化两个播放器,但具体播放器 class 应该以更通用的方式实现,以便以后可以重用。这在添加几个新派系的情况下也非常重要,您不想花时间回到您的玩家 class。
代码示例
要构建并 运行 它,请复制 Main.java,然后 javac Main.java
和 java Main
结果应该是
// Factories ----------------------------------------
abstract class AbsUnitFactory {
public abstract Warrior creaWarrior();
public abstract Peon creaPeon();
}
class OrcFactory extends AbsUnitFactory {
public Warrior creaWarrior() {
return new OrcWarrior();
}
public Peon creaPeon() {
return new OrcPeon();
}
}
class HumanFactory extends AbsUnitFactory {
public Warrior creaWarrior() {
return new HumanWarrior();
}
public Peon creaPeon() {
return new HumanPeon();
}
}
abstract class Unit {
public abstract String getRole();
public abstract String getFaction();
@Override
public String toString() {
String str = new String();
str += "[UNIT]\n";
str += " Role: " + this.getRole() + "\n";
str += " Faction: " + this.getFaction() + "\n";
return str;
}
}
// Warrior Units ----------------------------------------
abstract class Warrior extends Unit {
@Override
public String getRole() {
return "I'm a badass Warrior with the biggest sword!";
}
}
class OrcWarrior extends Warrior {
@Override
public String getFaction() {
return "Orc";
}
}
class HumanWarrior extends Warrior {
@Override
public String getFaction() {
return "Human";
}
}
// Peon Units ----------------------------------------
abstract class Peon extends Unit {
@Override
public String getRole() {
return "I'm a little simple peon... Ready to work.";
}
}
class HumanPeon extends Peon {
@Override
public String getFaction() {
return "Human";
}
}
class OrcPeon extends Peon {
@Override
public String getFaction() {
return "Orc";
}
}
// Main components ----------------------------------------
class Player {
private AbsUnitFactory factory;
private Peon myPeon;
private Warrior myWarrior;
public Player(AbsUnitFactory pFactory) {
this.factory = pFactory;
this.myPeon = this.factory.creaPeon();
this.myWarrior = this.factory.creaWarrior();
}
@Override
public String toString() {
return this.myPeon.toString() + this.myWarrior.toString();
}
}
class Main {
public static void main(String[] args) {
AbsUnitFactory humanFactory = new HumanFactory();
AbsUnitFactory orcFactory = new OrcFactory();
Player humanPlayer = new Player(humanFactory);
Player orcPlayer = new Player(orcFactory);
System.out.println("***** Human player *****");
System.out.println(humanPlayer.toString());
System.out.println("***** Orce player *****");
System.out.println(orcPlayer.toString());
}
}
查看玩家 class 如何被任何派系重复使用,唯一定义 派系使用的行是工厂。 (您甚至可以添加一个单例)。
更多资源
这些是我非常欣赏的书(关于设计模式)
- Head first 设计模式(http://shop.oreilly.com/product/9780596007126.do)
- 设计模式,可重用对象的元素(https://www.barnesandnoble.com/w/design-patterns-erich-gamma/1100886879)