• 再谈简单工厂模式,工厂方法模式,抽象工厂模式


    简单工厂模式

    基本简介  从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

      实现方式(附图)

      简单工厂模式的UML类图(见右图)

      简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。

      该模式中包含的角色及其职责

      工厂(Creator)角色

      简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。

      抽象产品(Product)角色

      简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

      具体产品(Concrete Product)角色

      是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

    优缺点

      优点

      工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。

      缺点

      由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。

      当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;

      这些缺点在工厂方法模式中得到了一定的克服。

      使用场景

      工厂类负责创建的对象比较少;

      客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;

    由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。

     

    工厂方法模式

    工厂方法(Factory Method)模式

      工厂方法的结构

    简介

      工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

      工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。

      工厂方法模式的对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不再负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。

      工厂方法模式(Factory Method pattern)是最典型的模板方法模式(Templete Method pattern)应用。

    工厂方法模式角色与结构

    抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。

      具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。

      抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。

      具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。

    工厂方法模式的应用

      工厂方法经常用在以下两种情况中:

      第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。Java Collection中的iterator() 方法即属于这种情况。

    第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。

    抽象工厂模式

    抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据LSP原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。

    目录

    定义

    简介

    产品族

    抽象工厂角色

    1. 具体工厂类1:

    2. 具体工厂类2:

    抽象产品类A

    1. 抽象产品类B:

    2. 具体产品类ProdcutA1:

    3. 具体产品类ProdcutA2:

    4. 具体产品类ProductB1:

    使用情况

    在农场系统的实现

    另一个模式

    OCP

    与其他设计模式的关系

    展开

    定义

      为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类

    简介

      当每个抽象产品都有多于一个的具体子类的时候,工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产品角色都有两个具体产品。抽象工厂模式提供两个具体工厂角色,分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。

      每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构。

    产品族

      是指位于不同产品等级结构中,功能相关联的产品组成的家族。一般是位于不同的等级结构中的相同位置上。显然,每一个产品族中含有产品的数目,与产品等级结构的数目是相等的,形成一个二维的坐标系,水平坐标是产品等级结构,纵坐标是产品族。叫做相图。

      当有多个不同的等级结构的产品时,如果使用工厂方法模式就势必要使用多个独立的工厂等级结构来对付这三个产品的等级结构。如果这些产品等级结构是平行的,会导致多个平行的工厂等级结构。

      抽象工厂模式使用同一个 工厂等级结构负责三个不同产品等级结构产品对象的创建。

      对于每一个产品族,都有一个具体工厂。而每一个具体工厂创建属于同一个产品族,但是分属于不同等级结构的产品。

      通过引进抽象工厂模式,可以处理具有相同(或者相似)等级结构的多个产品族中的产品对象的创建问题。

      由于每个具体工厂角色都需要负责两个不同等级结构的产品对象的创建,因此每个工厂角色都需要提供两个工厂方法,分别用于创建两个等级结构的产品。既然每个具体工厂角色都需要实现这两个工厂方法,所以具有一般性,不妨抽象出来,移动到抽象工厂角色中加以声明。

    抽象工厂角色

      public interface Creator{

      public ProductA factoryA();

      public ProductB factoryB();

      }

    具体工厂类1:

      public class ConcreteCreator1 implements Creator{

      public ProductA factoryA(){

      return new ProductA1();

      }

      public ProductB factoryB(){

      return new ProductB1();

      }

      }

    具体工厂类2:

      public class ConcreteCreator2 implements Creator{

      public ProductA factoryA(){

      return new ProductA2();

      }

      public ProductB factoryB(){

      return new ProductB2();

      }

      }

      一般而言,有多少个产品等级结构,就会在工厂角色中发现多少个工厂方法。每一个产品等级结构中有多少个具体的产品,就有多少个产品族,也就会在工厂等级结构中发现多少个具体工厂。

    抽象产品类A

      public interface ProductA

      {

      }

    抽象产品类B:

      public interface ProductB

      {

      }

    具体产品类ProdcutA1:

      public class ProductA1 implements ProductA

      {

      public ProductA1()

      {

      }

      }

    具体产品类ProdcutA2:

      public class ProductA2 implements ProductA

      {

      public ProductA2()

      {

      }

      }

    具体产品类ProductB1:

      public class ProductB1 implements ProductB

      {

      public ProductB1()

      {

      }

      }

      public class ProductB2 implements ProductB

      {

      public ProductB2()

      {

      }

      }

      在真实的系统中,产品等级结构的数目与每个产品等级结构中产品的数目(产品族)一般是不相等的。

    使用情况

      1.系统不依赖于产品类实例如何被创建,组合和表达的细节。

      2.系统的产品有多于一个的产品族,而系统只消费其中某一族的产品(抽象工厂模式的原始用意Unix&Windows)

      Button--->UnixButton/WinButton

      Text----->UnixText/WinText

      Unix产品族和Windows产品族,不会同时使用。

      Factory--->UnixFactory/WinFactory

      3.同属于同一个产品族是在一起使用的。这一约束必须在系统的设计中体现出来。

      4.系统提供一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于实现。

    在农场系统的实现

      //两种抽象产品:水果、蔬菜

      public interface Fruit

      {

      }

      public interface Veggie

      {

      }

      //四种具体产品:北方水果,热带水果,北方蔬菜,热带蔬菜

      //Northern Fruit

      public class NorthernFruit implements Fruit

      {

      private String name;

      public NorthernFruit(String name)

      {

      }

      public String getName()

      {

      return name;

      }

      public void setName(String name)

      {

      this. name = name;

      }

      }

      //TropicalFruit

      public class TropicalFruit implements Fruit

      {

      private String name;

      public TropicalFruit(String name)

      {

      }

      public String getName()

      {

      return name;

      }

      public void setName(String name)

      {

      this. name = name;

      }

      }

      //NorthernVeggie

      public class NorthernVeggie implements Veggie

      {

      private String name;

      public NorthernVeggie(String name)

      {

      }

      public String getName()

      {

      return name;

      }

      public void setName(String name)

      {

      this. name = name;

      }

      }

      //TropicalVeggie

      public class TropicalVeggie implements Veggie

      {

      private String name;

      public TropicalVeggie(String name)

      {

      }

      public String getName()

      {

      return name;

      }

      public void setName(String name)

      {

      this. name = name;

      }

      }

      //抽象工厂角色

      public interface Gardener

      {

      public Fruit createFruit(String name);

      public Veggie createVeggie(String name);

      }

      //具体工厂角色:北方工厂,热带角色

      public class NorthernGardener implements Gardener

      {

      public Fruit createFruit(String name)

      {

      return new NorthernFruit(name);

      }

      public Veggie createVeggie(String name)

      {

      return new NorthernVeggie(name);

      }

      }

      public class TropicalGardener implements Gardener

      {

      public Fruit createFruit(String name)

      {

      return new TropicalFruit(name);

      }

      public Veggie createVeggie(String name)

      {

      return new TropicalVeggie(name);

      }

      }

      这样客户端只需要创建具体工厂的实例,然后调用工厂对象的工厂方法就可以得到所需要的产品对象。

      第二个例子:C++实现

      例子:数据库访问程序设计,不同的数据库访问方式可能不一样,

      为了抽象对对不同数据库的访问,可以将数据库隐藏起来,提供统一的访问方式,用多态进行实现

      #include <iostream>

      using namespace std;

      //用户表接口

      class IUser

      {

      public:

      virtual void Insert() = 0;

      virtual void GetUser() = 0;

      };

      //SqlServer数据库访问User

      class SqlServerUser : public IUser

      {

      public:

      void Insert()

      {

      cout<<"在SQL Server中给User表增加一条记录"<<endl;

      }

      void GetUser()

      {

      cout<<"在SQL Server中给User表获取一条记录"<<endl;

      }

      };

      //Access数据库访问User

      class AccessUser : public IUser

      {

      public:

      void Insert()

      {

      cout<<"在Access中给User表增加一条记录"<<endl;

      }

      void GetUser()

      {

      cout<<"在Access中User表获取一条记录"<<endl;

      }

      };

      //Department表接口

      class IDepartment

      {

      public:

      virtual void Insert() = 0;

      virtual void GetDepartment() = 0;

      };

      //SqlServer数据库访问Department

      class SqlServerDepartment : public IDepartment

      {

      public:

      void Insert()

      {

      cout<<"在SQL Server中给Department表增加一条记录"<<endl;

      }

      void GetDepartment()

      {

      cout<<"在SQL Server中Department获取一条记录"<<endl;

      };

      };

      //Access数据库访问Department

      class AccessDepartment : public IDepartment

      {

      public:

      void Insert()

      {

      cout<<"在Access中给Department表增加一条记录"<<endl;

      }

      void GetDepartment()

      {

      cout<<"在Access中Department获取一条记录"<<endl;

      };

      };

      //抽象工厂接口

      class IFactory

      {

      public:

      virtual IUser* CreateUser() = 0;

      virtual IDepartment* CreateDepartment() = 0;

      };

      //SqlServer工厂实现

      class SqlServerFactory : public IFactory

      {

      IUser* CreateUser()

      {

      return new SqlServerUser();

      }

      IDepartment* CreateDepartment()

      {

      return new SqlServerDepartment();

      }

      };

      //Access工厂实现

      class AccessFactory : public IFactory

      {

      IUser* CreateUser()

      {

      return new AccessUser();

      }

      IDepartment* CreateDepartment()

      {

      return new AccessDepartment();

      }

      };

      int main()

      {

      //创建工厂

      IFactory * pFactory = NULL;

      IUser * pUser = NULL;

      IDepartment * pDepartment = NULL;

      int choise;

      cout<<"选择数据库: ";

      cin>>choise;

      switch(choise)

      {

      case 1:

      pFactory= new SqlServerFactory(); //创建SqlServer访问的工厂

      break;

      case 2:

      pFactory = new AccessFactory(); //创建Access访问的工厂

      break;

      }

      //一致的操作

      pUser = pFactory->CreateUser();

      pDepartment= pFactory->CreateDepartment();

      pUser->Insert();

      pUser->GetUser();

      pDepartment->Insert();

      pDepartment->GetDepartment();

      return 0;

      }

    另一个模式

      微型计算机配件,这个系统所需要的产品族有两个,一个系列是PC系列,另一个系列是MAC系列。

      产品等级结构也有两个,一个是RAM,一个是CPU。

      //两个抽象产品

      public interface Cpu

      {

      }

      public interface Ram

      {

      }

      //四个具体产品

      public class PcCpu implements Cpu

      {

      }

      public class MacCpu implements Cpu

      {

      }

      public class PcRam implements Ram

      {

      }

      public class MacRam implements Ram

      {

      }

      //抽象工厂角色

      public interface ComputerProducer

      {

      Cpu createCpu();

      Ram createRam();

      }

      //两个具体工厂角色

      public class PcProducer implements ComputerProducer

      {

      public Cpu createCpu()

      {

      return new PcCpu();

      }

      public Ram createRam()

      {

      return new PcRam();

      }

      }

      public class MacProducer implements ComputerProducer

      {

      public Cpu createCpu()

      {

      return new MacCpu();

      }

      public Ram createRam()

      {

      return new MacRam();

      }

      }

      一般情况下,有多少个抽象产品,就有多少个工厂方法。(比如再增加一个PC与MAC不同的其他计算机配件,例如显卡)。

    OCP

      增加产品族。

      增加产品等级结构。

      在不改变产品等级结构的情况下,增加产品族就是意味着向每一个产品等级结构中增加一个或者多个新的具体产品角色,这时只需要向工厂等级结构中增加新的元素就可以了,具体的说,只需要增加新的具体工厂类就可以了。

      在产品族数目不变的情况下,增加产品等级结构,相当于增加一个与现有产品等级结构平行的一个新的产品等级结构,这时需要向修改所有的工厂角色,增加一个新的工厂方法,这是不支持OCP的。

      Producer

      PcProducer MacProducer

      CPU

      PcCPU MacCPU

      RAM

      PcRAM MacCPU

      在上面的结构中,增加产品族相当于增加一个新的厂商,比如Sun的CPU和RAM,这时,只需要增加一个SunProducer即可。

      而增加一个新的产品等级结构相当于增加一个显卡,而显卡也有Pc和Mac之分,那么对于所有的Producer,都需要增加一个方法:createCard()

    与其他设计模式的关系

      单例模式:具体工厂类可以设计成单例类,一个单例类只有一个实例,它自己向外界提供自己唯一的实例。很显然,在农场系统中,只需要NorthernGardener和TropicalGardener的一个实例就可以了。而在计算机生产的例子中,PcProducer和RamProducer也分别只需要一个实例。

      工厂的工厂:工厂角色与抽象产品角色合并(简单工厂模式java.util.DateFormat),在抽象工厂模式中,抽象工厂类可以有静态方法,这个方法根据参数的值,返回对应的具体工厂类实例,但是其返回值类型是抽象工厂类型,这样可以在多态性的保证之下,允许静态工厂方法自行决定哪一个具体工厂符合要求。

      //计算机生产抽象工厂角色

      abstract public class ComputerProducer

      {

      public static ComputerProducer getProducer(String which)

      {

      if (which.equalsIgnoreCase("PC"))

      {

      return new PcProducer();

      }

      else if (which.equalsIgnoreCase("Mac"))

      {

      return new MacProducer();

      }

      else

      {

      return null;

      }

      }

      }

      工厂的工厂:工厂角色可以和具体产品角色合并(简单工厂模式),在抽象工厂模式中,每一个具体工厂类可以有一个静态方法,其返回值类型是该具体工厂类自己。

      public class MacProducer extends ComputerProducer

      {

      private static MacProducer producer = new MacProducer();

      private MacProducer() {

      }

      public Cpu createCpu()

      {

      return new MacCpu();

      }

      public Ram createRam()

      {

      return new PcRam();

      }

      public static MacProducer getInstance()

      {

      return producer;

      }

      }

      女娲造万物的故事:

      神绳(+举绳造物())

      阴绳 阳绳

      人

      女人 男人

      动物

      雌性 雄性

      在JAVA语言的AWT库中,使用了抽象工厂模式创建分水域不同操作系统的Peer构件(与本地系统相关的GUI组件)。

  • 相关阅读:
    nodejs 不支持 typescript (...paramName:any[])剩余参数。变相支持方式。
    centos7安装nodejs
    .Net Core Linux centos7行—jenkins linux 构建.net core web app
    asp.net core 编译mvc,routing,security源代码进行本地调试
    发现一个很N且免费的html5拓扑图 关系图 生成组件
    Quill编辑器介绍及扩展
    vs2017 rc 离线安装包制作
    单体架构风格
    GlusterFS 安装 on centos7
    Expect 安装 on centos7
  • 原文地址:https://www.cnblogs.com/skyofbitbit/p/2780332.html
Copyright © 2020-2023  润新知