工厂模式。 什么时候使用工厂方法?

发布于 2024-07-05 19:29:54 字数 33 浏览 6 评论 0原文

什么时候在对象中使用工厂方法而不是工厂类是个好主意?

When is it a good idea to use factory methods within an object instead of a Factory class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

指尖微凉心微凉 2024-07-12 19:29:54

清楚地区分使用工厂或工厂方法背后的想法很重要。
两者都是为了解决相互排斥的不同类型的对象创建问题。

让我们具体说明一下“工厂方法”:

首先,当您开发库或 API 并将用于进一步的应用程序开发时,工厂方法是创建模式的最佳选择之一。 背后的原因; 我们知道何时创建具有所需功能的对象,但对象的类型将保持未定状态,或者将由传递的动态参数决定

现在的要点是,通过使用工厂模式本身可以实现大致相同的效果,但是如果将工厂模式用于上述突出显示的问题,则会给系统带来一个巨大的缺点,那就是您创建不同对象(子类对象)的逻辑将特定于某些业务条件,因此将来当您需要为其他平台扩展库的功能时(从技术上讲,您需要添加更多基本接口或抽象类的子类,以便工厂除了现有对象之外还将返回这些对象基于一些动态参数)然后每次你需要改变(扩展)工厂类的逻辑,这将是昂贵的操作并且从设计角度来看不好。
另一方面,如果使用“工厂方法”模式来执行相同的操作,那么您只需要创建附加功能(子类)并通过注入动态注册它,这不需要更改您的基本代码。

interface Deliverable 
{
    /*********/
}

abstract class DefaultProducer 
{

    public void taskToBeDone() 
    {   
        Deliverable deliverable = factoryMethodPattern();
    }
    protected abstract Deliverable factoryMethodPattern();
}

class SpecificDeliverable implements Deliverable 
{
 /***SPECIFIC TASK CAN BE WRITTEN HERE***/
}

class SpecificProducer extends DefaultProducer 
{
    protected Deliverable factoryMethodPattern() 
    {
        return new SpecificDeliverable();
    }
}

public class MasterApplicationProgram 
{
    public static void main(String arg[]) 
    {
        DefaultProducer defaultProducer = new SpecificProducer();
        defaultProducer.taskToBeDone();
    }
}

It is important to clearly differentiate the idea behind using factory or factory method.
Both are meant to address mutually exclusive different kind of object creation problems.

Let's be specific about "factory method":

First thing is that, when you are developing library or APIs which in turn will be used for further application development, then factory method is one of the best selections for creation pattern. Reason behind; We know that when to create an object of required functionality(s) but type of object will remain undecided or it will be decided ob dynamic parameters being passed.

Now the point is, approximately same can be achieved by using factory pattern itself but one huge drawback will introduce into the system if factory pattern will be used for above highlighted problem, it is that your logic of crating different objects(sub classes objects) will be specific to some business condition so in future when you need to extend your library's functionality for other platforms(In more technically, you need to add more sub classes of basic interface or abstract class so factory will return those objects also in addition to existing one based on some dynamic parameters) then every time you need to change(extend) the logic of factory class which will be costly operation and not good from design perspective.
On the other side, if "factory method" pattern will be used to perform the same thing then you just need to create additional functionality(sub classes) and get it registered dynamically by injection which doesn't require changes in your base code.

interface Deliverable 
{
    /*********/
}

abstract class DefaultProducer 
{

    public void taskToBeDone() 
    {   
        Deliverable deliverable = factoryMethodPattern();
    }
    protected abstract Deliverable factoryMethodPattern();
}

class SpecificDeliverable implements Deliverable 
{
 /***SPECIFIC TASK CAN BE WRITTEN HERE***/
}

class SpecificProducer extends DefaultProducer 
{
    protected Deliverable factoryMethodPattern() 
    {
        return new SpecificDeliverable();
    }
}

public class MasterApplicationProgram 
{
    public static void main(String arg[]) 
    {
        DefaultProducer defaultProducer = new SpecificProducer();
        defaultProducer.taskToBeDone();
    }
}
烟花易冷人易散 2024-07-12 19:29:54

我喜欢从我的类是“人”的角度来思考设计模式,这些模式是人们相互交谈的方式。

所以,对我来说,工厂模式就像一个招聘机构。 你有人需要不同数量的工人。 这个人可能知道他们所雇用的人需要的一些信息,但仅此而已。

因此,当他们需要新员工时,他们会致电招聘机构并告诉他们需要什么。 现在,要实际雇用某人,您需要了解很多东西 - 福利、资格验证等。但雇用的人不需要知道这些 - 招聘机构会处理所有这些那。

同样,使用工厂允许消费者创建新对象,而无需知道它们如何创建的详细信息,或者它们的依赖项是什么 - 他们只需要提供他们真正想要的信息。

public interface IThingFactory
{
    Thing GetThing(string theString);
}

public class ThingFactory : IThingFactory
{
    public Thing GetThing(string theString)
    {
        return new Thing(theString, firstDependency, secondDependency);
    }
}

因此,现在 ThingFactory 的消费者可以获取一个 Thing,而无需了解该 Thing 的依赖关系,除了来自消费者的字符串数据。

I like thinking about design pattens in terms of my classes being 'people,' and the patterns are the ways that the people talk to each other.

So, to me the factory pattern is like a hiring agency. You've got someone that will need a variable number of workers. This person may know some info they need in the people they hire, but that's it.

So, when they need a new employee, they call the hiring agency and tell them what they need. Now, to actually hire someone, you need to know a lot of stuff - benefits, eligibility verification, etc. But the person hiring doesn't need to know any of this - the hiring agency handles all of that.

In the same way, using a Factory allows the consumer to create new objects without having to know the details of how they're created, or what their dependencies are - they only have to give the information they actually want.

public interface IThingFactory
{
    Thing GetThing(string theString);
}

public class ThingFactory : IThingFactory
{
    public Thing GetThing(string theString)
    {
        return new Thing(theString, firstDependency, secondDependency);
    }
}

So, now the consumer of the ThingFactory can get a Thing, without having to know about the dependencies of the Thing, except for the string data that comes from the consumer.

哥,最终变帅啦 2024-07-12 19:29:54

我个人认为单独的 Factory 类有意义的一种情况是,当您尝试创建的最终对象依赖于其他几个对象时。 例如,在 PHP 中:假设您有一个 House 对象,该对象又具有一个 Kitchen 和一个 LivingRoom 对象,并且 LivingRoom 对象内部也有一个 TV 对象。

实现此目的的最简单方法是让每个对象在其构造方法上创建其子对象,但如果属性相对嵌套,当您的 House 创建失败时,您可能会花一些时间尝试准确隔离哪些属性失败。

另一种方法是执行以下操作(依赖注入,如果您喜欢这个花哨的术语):

$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);

这里,如果创建 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),同时集中化,使其更易于维护。 使用单独的工厂可能是有益的还有其他原因(例如可测试性),但我发现这个特定的用例可以最好地说明工厂类如何有用。

One situation where I personally find separate Factory classes to make sense is when the final object you are trying to create relies on several other objects. E.g, in PHP: Suppose you have a House object, which in turn has a Kitchen and a LivingRoom object, and the LivingRoom object has a TV object inside as well.

The simplest method to achieve this is having each object create their children on their construct method, but if the properties are relatively nested, when your House fails creating you will probably spend some time trying to isolate exactly what is failing.

The alternative is to do the following (dependency injection, if you like the fancy term):

$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);

Here if the process of creating a House fails there is only one place to look, but having to use this chunk every time one wants a new House is far from convenient. Enter the Factories:

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();

Thanks to the factory here the process of creating a House is abstracted (in that you don't need to create and set up every single dependency when you just want to create a House) and at the same time centralized which makes it easier to maintain. There are other reasons why using separate Factories can be beneficial (e.g. testability) but I find this specific use case to illustrate best how Factory classes can be useful.

早茶月光 2024-07-12 19:29:54

工厂方法应被视为构造函数的替代方案 - 大多数情况下当构造函数的表达能力不够时,即。

class Foo{
  public Foo(bool withBar);
}

表达能力不如:

class Foo{
  public static Foo withBar();
  public static Foo withoutBar();
}

当您需要复杂的过程来构造对象时,当构造需要实际类不需要的依赖项时,当您需要构造不同的对象等时,工厂类非常有用。

Factory methods should be considered as an alternative to constructors - mostly when constructors aren't expressive enough, ie.

class Foo{
  public Foo(bool withBar);
}

is not as expressive as:

class Foo{
  public static Foo withBar();
  public static Foo withoutBar();
}

Factory classes are useful when you need a complicated process for constructing the object, when the construction need a dependency that you do not want for the actual class, when you need to construct different objects etc.

把人绕傻吧 2024-07-12 19:29:54

当您需要多个具有相同参数类型但具有不同行为的“构造函数”时,它们也很有用。

They're also useful when you need several "constructors" with the same parameter type but with different behavior.

拧巴小姐 2024-07-12 19:29:54

在以下情况下,在对象内部使用工厂方法是个好主意:

  1. 对象的类不知道它必须创建哪些确切的子类
  2. 子类指定
  3. 对象的类被设计为使其创建的对象由对象的 类将其职责委托给辅助子类,并且不知道具体的类将承担这些职责。

在以下情况下使用抽象工厂类是个好主意:

  1. 您的对象不应依赖于其内部对象的方式创建和设计
  2. 链接对象组应该一起使用,并且您需要满足此约束
  3. 对象应该由几个可能的链接对象系列之一进行配置,这些链接对象将成为父对象的一部分
  4. 需要共享显示接口的子对象仅但不是实施

It is good idea to use factory methods inside object when:

  1. Object's class doesn't know what exact sub-classes it have to create
  2. Object's class is designed so that objects it creates were specified by sub-classes
  3. Object's class delegates its duties to auxiliary sub-classes and doesn't know what exact class will take these duties

It is good idea to use abstract factory class when:

  1. Your object shouldn't depend on how its inner objects are created and designed
  2. Group of linked objects should be used together and you need to serve this constraint
  3. Object should be configured by one of several possible families of linked objects that will be a part of your parent object
  4. It is required to share child objects showing interfaces only but not an implementation
谷夏 2024-07-12 19:29:54

问题陈述:使用工厂方法创建游戏工厂,定义游戏界面。

代码片段:

import java.util.HashMap;


/* Product interface as per UML diagram */
interface Game{
    /* createGame is a complex method, which executes a sequence of game steps */
    public void createGame();
}

/* ConcreteProduct implementation as per UML diagram */
class Chess implements Game{
    public Chess(){
        
    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Chess game");
        System.out.println("Opponents:2");
        System.out.println("Define 64 blocks");
        System.out.println("Place 16 pieces for White opponent");
        System.out.println("Place 16 pieces for Black opponent");
        System.out.println("Start Chess game");
        System.out.println("---------------------------------------");
    }
}
class Checkers implements Game{
    public Checkers(){
       
    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Checkers game");
        System.out.println("Opponents:2 or 3 or 4 or 6");
        System.out.println("For each opponent, place 10 coins");
        System.out.println("Start Checkers game");
        System.out.println("---------------------------------------");
    }
}
class Ludo implements Game{
    public Ludo(){
        
    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Ludo game");
        System.out.println("Opponents:2 or 3 or 4");
        System.out.println("For each opponent, place 4 coins");
        System.out.println("Create two dices with numbers from 1-6");
        System.out.println("Start Ludo game");
        System.out.println("---------------------------------------");
    }
}

/* Creator interface as per UML diagram */
interface IGameFactory {
    public Game getGame(String gameName);
}

/* ConcreteCreator implementation as per UML diagram */
class GameFactory implements IGameFactory {
        
     HashMap<String,Game> games = new HashMap<String,Game>();
    /*  
        Since Game Creation is complex process, we don't want to create game using new operator every time.
        Instead we create Game only once and store it in Factory. When client request a specific game, 
        Game object is returned from Factory instead of creating new Game on the fly, which is time consuming
    */
    
    public GameFactory(){
        
        games.put(Chess.class.getName(),new Chess());
        games.put(Checkers.class.getName(),new Checkers());
        games.put(Ludo.class.getName(),new Ludo());        
    }
    public Game getGame(String gameName){
        return games.get(gameName);
    }
}

public class NonStaticFactoryDemo{
    public static void main(String args[]){
        if ( args.length < 1){
            System.out.println("Usage: java FactoryDemo gameName");
            return;
        }
     
        GameFactory factory = new GameFactory();
        Game game = factory.getGame(args[0]);
        if ( game != null ){                    
            game.createGame();
            System.out.println("Game="+game.getClass().getName());
        }else{
            System.out.println(args[0]+  " Game does not exists in factory");
        }           
    }
}

输出:

java NonStaticFactoryDemo Chess
---------------------------------------
Create Chess game
Opponents:2
Define 64 blocks
Place 16 pieces for White opponent
Place 16 pieces for Black opponent
Start Chess game
---------------------------------------
Game=Chess

此示例通过实现 FactoryMethod 显示了一个 Factory 类。

  1. Game 是所有类型游戏的界面。 它定义了复杂的方法:createGame()

  2. Chess、Ludo、Checkers是游戏的不同变体,它们为createGame()提供了实现

  3. public Game getGame(String gameName)IGameFactory 类中的 FactoryMethod

  4. GameFactory 预先创建不同类型的构造函数中的游戏。 它实现了 IGameFactory 工厂方法。

  5. 游戏名称作为命令行参数传递给NotStaticFactoryDe​​mo

  6. GameFactory 中的getGame 接受游戏名称并返回相应的 Game 对象。


定义来自维基百科/四人帮(《设计模式:可重用面向对象软件的元素》一书)

工厂:创建对象而不向客户端公开实例化逻辑。

工厂方法定义用于创建对象的接口,但让子类决定实例化哪个类。 工厂方法让类将其使用的实例化推迟到子类。”(四人帮)

用例:

何时使用:客户端不知道它将使用哪些具体类需要在运行时创建对象,它只是想获得一个可以完成这项工作的类。

Problem statement: Create a Factory of Games by using Factory Methods, which defines the game interface.

Code snippet:

import java.util.HashMap;


/* Product interface as per UML diagram */
interface Game{
    /* createGame is a complex method, which executes a sequence of game steps */
    public void createGame();
}

/* ConcreteProduct implementation as per UML diagram */
class Chess implements Game{
    public Chess(){
        
    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Chess game");
        System.out.println("Opponents:2");
        System.out.println("Define 64 blocks");
        System.out.println("Place 16 pieces for White opponent");
        System.out.println("Place 16 pieces for Black opponent");
        System.out.println("Start Chess game");
        System.out.println("---------------------------------------");
    }
}
class Checkers implements Game{
    public Checkers(){
       
    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Checkers game");
        System.out.println("Opponents:2 or 3 or 4 or 6");
        System.out.println("For each opponent, place 10 coins");
        System.out.println("Start Checkers game");
        System.out.println("---------------------------------------");
    }
}
class Ludo implements Game{
    public Ludo(){
        
    }
    public void createGame(){
        System.out.println("---------------------------------------");
        System.out.println("Create Ludo game");
        System.out.println("Opponents:2 or 3 or 4");
        System.out.println("For each opponent, place 4 coins");
        System.out.println("Create two dices with numbers from 1-6");
        System.out.println("Start Ludo game");
        System.out.println("---------------------------------------");
    }
}

/* Creator interface as per UML diagram */
interface IGameFactory {
    public Game getGame(String gameName);
}

/* ConcreteCreator implementation as per UML diagram */
class GameFactory implements IGameFactory {
        
     HashMap<String,Game> games = new HashMap<String,Game>();
    /*  
        Since Game Creation is complex process, we don't want to create game using new operator every time.
        Instead we create Game only once and store it in Factory. When client request a specific game, 
        Game object is returned from Factory instead of creating new Game on the fly, which is time consuming
    */
    
    public GameFactory(){
        
        games.put(Chess.class.getName(),new Chess());
        games.put(Checkers.class.getName(),new Checkers());
        games.put(Ludo.class.getName(),new Ludo());        
    }
    public Game getGame(String gameName){
        return games.get(gameName);
    }
}

public class NonStaticFactoryDemo{
    public static void main(String args[]){
        if ( args.length < 1){
            System.out.println("Usage: java FactoryDemo gameName");
            return;
        }
     
        GameFactory factory = new GameFactory();
        Game game = factory.getGame(args[0]);
        if ( game != null ){                    
            game.createGame();
            System.out.println("Game="+game.getClass().getName());
        }else{
            System.out.println(args[0]+  " Game does not exists in factory");
        }           
    }
}

output:

java NonStaticFactoryDemo Chess
---------------------------------------
Create Chess game
Opponents:2
Define 64 blocks
Place 16 pieces for White opponent
Place 16 pieces for Black opponent
Start Chess game
---------------------------------------
Game=Chess

This example shows a Factory class by implementing a FactoryMethod.

  1. Game is the interface for all type of games. It defines complex method: createGame()

  2. Chess, Ludo, Checkers are different variants of games, which provide implementation to createGame()

  3. public Game getGame(String gameName) is FactoryMethod in IGameFactory class

  4. GameFactory pre-creates different type of games in constructor. It implements IGameFactory factory method.

  5. game Name is passed as command line argument to NotStaticFactoryDemo

  6. getGame in GameFactory accepts a game name and returns corresponding Game object.

Definition from Wikipedia/Gang of Four ( Design Patterns: Elements of Reusable Object-Oriented Software book)

Factory: Creates objects without exposing the instantiation logic to the client.

Factory Method: Define an interface for creating an object, but let subclasses decide which class to instantiate. The Factory method lets a class defer instantiation it uses to subclasses." (Gang Of Four)

Use case:

When to use: Client doesn't know which concrete classes it will be required to create the object at runtime. It just wants to get a class that will do the job.

笨死的猪 2024-07-12 19:29:54

当工厂类返回的对象类型具有私有构造函数时,当不同的工厂类在返回的对象上设置不同的属性时,或者当特定的工厂类型与其返回的具体类型耦合时,工厂类非常有用。

WCF 使用 ServiceHostFactory 类在不同情况下检索 ServiceHost 对象。 IIS 使用标准 ServiceHostFactory 检索 .svc 文件的 ServiceHost 实例,但 WebScriptServiceHostFactory 用于将序列化返回到 JavaScript 客户端的服务。 ADO.NET 数据服务有其自己特殊的 DataServiceHostFactory,而 ASP.NET 也有其 ApplicationServicesHostFactory,因为其服务具有私有构造函数。

如果您只有一个类使用工厂,那么您可以只在该类中使用工厂方法。

Factory classes are useful for when the object type that they return has a private constructor, when different factory classes set different properties on the returning object, or when a specific factory type is coupled with its returning concrete type.

WCF uses ServiceHostFactory classes to retrieve ServiceHost objects in different situations. The standard ServiceHostFactory is used by IIS to retrieve ServiceHost instances for .svc files, but a WebScriptServiceHostFactory is used for services that return serializations to JavaScript clients. ADO.NET Data Services has its own special DataServiceHostFactory and ASP.NET has its ApplicationServicesHostFactory since its services have private constructors.

If you only have one class that's consuming the factory, then you can just use a factory method within that class.

看春风乍起 2024-07-12 19:29:54

这确实是一个品味问题。 工厂类可以根据需要进行抽象/接口,而工厂方法重量更轻(并且也往往是可测试的,因为它们没有定义的类型,但它们需要一个众所周知的注册点,类似于服务定位器,但用于定位工厂方法)。

It's really a matter of taste. Factory classes can be abstracted/interfaced away as necessary, whereas factory methods are lighter weight (and also tend to be testable, since they don't have a defined type, but they will require a well-known registration point, akin to a service locator but for locating factory methods).

情栀口红 2024-07-12 19:29:54

考虑一个必须设计 Order 和 Customer 类的场景。 为了简单性和初始要求,您不需要 Order 类的工厂,并用许多“new Order()”语句填充您的应用程序。 一切进展顺利。

现在出现了一个新的要求,即如果没有客户关联(新依赖项),则无法实例化订单对象。 现在您有以下考虑。

1-您创建构造函数重载,该重载仅适用于新的实现。 (不能接受的)。
2-您更改 Order() 签名并更改每个调用。 (这不是一个好的做法,而且是真正的痛苦)。

相反,如果您已经为订单类创建了一个工厂,那么您只需更改一行代码就可以了。 我建议几乎每个聚合关联都使用工厂类。 希望有帮助。

Consider a scenario when you have to design an Order and Customer class. For simplicity and initial requirements you do not feel need of factory for Order class and fill your application with many 'new Order()' statements. Things are working well.

Now a new requirement comes into picture that Order object cannot be instantiated without Customer association (new dependency). Now You have following considerations.

1- You create constructor overload which will work only for new implementations. (Not acceptable).
2- You change Order() signatures and change each and every invokation. (Not a good practice and real pain).

Instead If you have created a factory for Order Class you only have to change one line of code and you are good to go. I suggest Factory class for almost every aggregate association. Hope that helps.

无戏配角 2024-07-12 19:29:54

GOF 定义:

定义一个用于创建对象的接口,但让子类决定实例化哪个类。 工厂方法让类将实例化推迟到子类。

通用示例:

public abstract class Factory<T> {

    public abstract T instantiate(Supplier<? extends T> supplier);

}

具体类

public class SupplierFactory<T> extends Factory<T> {

    @Override
    public T instantiate(Supplier<? extends T> supplier) {
        return supplier.get();
    }
}

实现

public class Alpha implements BaseInterface {
    @Override
    public void doAction() {
        System.out.println("The Alpha executed");
    }
}

public class Beta implements BaseInterface {
    @Override
    public void doAction() {
        System.out.println("The Beta executed");
    }
}

public interface BaseInterface {
    void doAction();
}

public class Main {
    public static void main(String[] args) {
        Factory<BaseInterface> secondFactory = new SupplierFactory<>();
        secondFactory.instantiate(Beta::new).doAction();
        secondFactory.instantiate(Alpha::new).doAction();
    }
}

简介优点

  • 您将可能变化的代码与不变的代码分开(即,使用简单工厂模式的优点是仍然存在)。 这种技术可以帮助您轻松维护代码。
  • 你的代码没有紧密耦合; 因此,您可以随时在系统中添加新的类,如 Lion、Beer 等,而无需修改现有体系结构。 所以,你遵循了“禁止修改,开放扩展”的原则。

GOF Definition :

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory method lets a class defer instantiation to subclasses.

Generic example :

public abstract class Factory<T> {

    public abstract T instantiate(Supplier<? extends T> supplier);

}

The concrete class

public class SupplierFactory<T> extends Factory<T> {

    @Override
    public T instantiate(Supplier<? extends T> supplier) {
        return supplier.get();
    }
}

The Implementation

public class Alpha implements BaseInterface {
    @Override
    public void doAction() {
        System.out.println("The Alpha executed");
    }
}

public class Beta implements BaseInterface {
    @Override
    public void doAction() {
        System.out.println("The Beta executed");
    }
}

public interface BaseInterface {
    void doAction();
}

public class Main {
    public static void main(String[] args) {
        Factory<BaseInterface> secondFactory = new SupplierFactory<>();
        secondFactory.instantiate(Beta::new).doAction();
        secondFactory.instantiate(Alpha::new).doAction();
    }
}

Brief advantages

  • You are separating code that can vary from the code that does not vary (i.e., the advantages of using a simple factory pattern is still present). This technique helps you easily maintain code.
  • Your code is not tightly coupled; so, you can add new classes like Lion, Beer, and so forth, at any time in the system without modifying the existing architecture. So, you have followed the “closed for modification but open for extension” principle.
写给空气的情书 2024-07-12 19:29:54

工厂类更加重量级,但给你带来了一定的优势。 如果您需要从多个原始数据源构建对象,它们允许您仅将构建逻辑(也可能是数据的聚合)封装在一个位置。 在那里可以抽象地测试它,而不用关心对象接口。

我发现这是一个有用的模式,特别是当我无法替换 ORM 且不充分并且希望从数据库表连接或存储过程有效实例化许多对象时。

Factory classes are more heavyweight, but give you certain advantages. In cases when you need to build your objects from multiple, raw data sources they allow you to encapsulate only the building logic (and maybe the aggregation of the data) in one place. There it can be tested in abstract without being concerned with the object interface.

I have found this a useful pattern, particularly where I am unable to replace and inadequate ORM and want to efficiently instantiate many objects from DB table joins or stored procedures.

一枫情书 2024-07-12 19:29:54

我的简短解释是,当我们没有足够的信息来创建具体对象时,我们会使用工厂模式。 我们要么不知道依赖关系,要么不知道对象的类型。 而且我们几乎总是不知道它们,因为这是运行时提供的信息。

示例:我们知道必须创建一个车辆对象,但我们不知道它是否会飞或在地面上工作。

My short explanation will be that we use the factory pattern when we don't have enough information to create a concrete object. We either don't know the dependencies or we don't know the type of the object. And almost always we don't know them because this is information that comes at runtime.

Example: we know that we have to create a vehicle object but we don't know if it flies or it works on ground.

吃不饱 2024-07-12 19:29:54

任何将需要使用的对象的对象创建推迟到其子类的类都可以视为工厂模式的示例。

我在另一个答案中详细提到了 https://stackoverflow.com/a/49110001/504133

Any class deferring the object creation to its sub class for the object it needs to work with can be seen as an example of Factory pattern.

I have mentioned in detail in an another answer at https://stackoverflow.com/a/49110001/504133

[浮城] 2024-07-12 19:29:54

我认为这取决于您想要为代码带来的松散耦合程度。

工厂方法可以很好地解耦事物,但工厂类不行。

换句话说,使用工厂方法比使用简单工厂(称为工厂类)更容易更改内容。

查看此示例: https://connected2know.com/programming/java-factory-pattern/ 。 现在,想象一下您想带一只新动物。 在工厂类中,您需要更改工厂,但在工厂方法中,不需要,您只需要添加一个新的子类。

I think it will depend of loose coupling degree that you want to bring to your code.

Factory method decouples things very well but factory class no.

In other words, it's easier to change things if you use factory method than if you use a simple factory (known as factory class).

Look into this example: https://connected2know.com/programming/java-factory-pattern/ . Now, imagine that you want to bring a new Animal. In Factory class you need to change the Factory but in the factory method, no, you only need to add a new subclass.

若能看破又如何 2024-07-12 19:29:54

我将工厂比作图书馆的概念。 例如,您可以拥有一个用于处理数字的库和另一个用于处理形状的库。 您可以将这些库的函数存储在逻辑命名的目录中,如 NumbersShapes。 这些是通用类型,可以包括整数、浮点数、双数、长整型或矩形、圆形、三角形、五边形(如果是形状)。

petter工厂使用多态性、依赖注入和控制反转。

工厂模式的既定目的是:定义用于创建对象的接口,但让子类决定实例化哪个类。 工厂方法让类将实例化推迟到子类。

因此,假设您正在构建一个操作系统或框架,并且正在构建所有离散组件。

这是 PHP 中工厂模式概念的一个简单示例。 我可能不是 100% 完全同意,但它只是作为一个简单的例子。 我不是专家。

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 );

I liken factories to the concept of libraries. For example you can have a library for working with numbers and another for working with shapes. You can store the functions of these libraries in logically named directories as Numbers or Shapes. These are generic types that could include integers, floats, dobules, longs or rectangles, circles, triangles, pentagons in the case of shapes.

The factory petter uses polymorphism, dependency injection and Inversion of control.

The stated purpose of the Factory Patterns is: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

So let's say that you are building an Operating System or Framework and you are building all the discrete components.

Here is a simple example of the concept of the Factory Pattern in PHP. I may not be 100% on all of it but it's intended to serve as a simple example. I am not an expert.

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 );
心舞飞扬 2024-07-12 19:29:54

如果你想在使用方面创建不同的对象。 它是有益的。

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;
      }
}

if you want to create a different object in terms of using. It is useful.

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;
      }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文