设计模式(1): 工厂模式

  工厂模式属于创建型设计模式(Creational Patterns),实现了“工厂”概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体类型的情况下创建对象的问题。工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。”
  创建一个对象常常需要复杂的过程,所以不适合包含在一个复合对象中。创建对象可能会导致大量的重复代码,可能会需要复合对象访问不到的信息,也可能提供不了足够级别的抽象,还可能并不是复合对象概念的一部分。工厂方法模式通过定义一个单独的创建对象的方法来解决这些问题。由子类实现这个方法来创建具体类型的对象。

1) 简单工厂模式(Simple Factory Pattern)
  简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,工厂对象通常包含一个或多个方法,用来创建这个工厂所能创建的各种类型的对象。这些方法可能接收参数,用来指定对象创建的方式,最后返回创建的对象。

  比如,一个程序要读取图像文件。程序支持多种图像格式,每种格式都有一个对应的ImageReader类用来读取图像。程序每次读取图像时,需要基于文件信息创建合适类型的ImageReader。这个选择逻辑可以包装在一个简单工厂中:

public class ImageReaderFactory {
    public static ImageReader imageReaderFactoryMethod(InputStream is) {
        ImageReader product = null;

        int imageType = determineImageType(is);
        switch (imageType) {
            case ImageReaderFactory.GIF:
                product = new GifReader(is);
            case ImageReaderFactory.JPEG:
                product = new JpegReader(is);
            //...
        }
        return product;
    }
}
你还可以先进行对产品进行注册
class ProductFactory
{
    private HashMap m_RegisteredProducts = new HashMap();

    public void registerProduct (String productID, Class productClass)
    {
        m_RegisteredProducts.put(productID, productClass);
    }

    public Product createProduct(String productID)
    {
        Class productClass = (Class)m_RegisteredProducts.get(productID);
        Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class });
        return (Product)productConstructor.newInstance(new Object[] { });
    }
}

总结:
  简单工厂模式主要包括三部分:
  1)Factory:学生会,负责实现创建所有实例。
  2)Product:部门,提供创建实例所共有的公共接口。
  3)ConcreteProduct:(组织部,宣传部,外联部)创建具体事例。

  简单工厂模式将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。
  简单工厂模式最大的问题在于工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背的。

工厂方法模式(Factory Method Pattern)
  上面提到简单工厂模式违背了开闭原则,那如何解决呢?
  工厂方法模式是简单工厂模式的衍生,完全实现‘开闭原则’,实现了可扩展,可以应用于产品结果复杂的场合。
  工厂方法模式对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个抽象工厂类不再负责产品的创建,仅负责具体工厂子类必须实现的接口,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。

public interface Product {  }

public abstract class Creator 
{
    public void anOperation() 
    {
        Product product = factoryMethod();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteProduct implements Product {  }

public class ConcreteCreator extends Creator 
{
    protected Product factoryMethod() 
    {
        return new ConcreteProduct();
    }
}

public class Client 
{
    public static void main( String arg[] ) 
    {
        Creator creator = new ConcreteCreator();
        creator.anOperation();
    }
}

总结:
  工厂方法模式其实是对简单工厂模式中工厂进行了进一步抽象,已解决开闭问题。
  工厂方法模式分为以下四部分:
  抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
  具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。
  抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。
  具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
  工厂方法的缺点也很明显,在添加新产品时,不仅需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。

抽象工厂模式
  抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构。
  当每个抽象产品都有多于一个的具体子类的时候,工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产品角色都有两个具体产品。抽象工厂模式提供两个具体工厂角色,分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。
  举个例子,商场里都有手机柜台和笔记本柜台,手机和笔记本都有苹果和联想品牌,如果你想要苹果的iPhone6,销售人员就会从手机柜台拿苹果的iPhone6,如果你想要联想的ThinkPad,销售人员就会从笔记本柜台拿联想的ThinkPad。这里的销售员就像是一个总的接口,一个抽象工厂,手机柜台和笔记本柜台就像两个具体工厂,苹果和联想就是抽象的产品,其各自生成的手机和笔记本就是具体的产品。

abstract class AbstractProductA{
    public abstract void operationA1();
    public abstract void operationA2();
}

class ProductA1 extends AbstractProductA{
    ProductA1(String arg){
        System.out.println("Hello "+arg);
    } // Implement the code here
    public void operationA1() { };
    public void operationA2() { };
}

class ProductA2 extends AbstractProductA{
    ProductA2(String arg){
        System.out.println("Hello "+arg);
    } // Implement the code here
    public void operationA1() { };
    public void operationA2() { };
}

abstract class AbstractProductB{
    //public abstract void operationB1();
    //public abstract void operationB2();
}

class ProductB1 extends AbstractProductB{
    ProductB1(String arg){
        System.out.println("Hello "+arg);
    } // Implement the code here
}

class ProductB2 extends AbstractProductB{
    ProductB2(String arg){
        System.out.println("Hello "+arg);
    } // Implement the code here
}

abstract class AbstractFactory{
    abstract AbstractProductA createProductA();
    abstract AbstractProductB createProductB();
}

class ConcreteFactory1 extends AbstractFactory{
    AbstractProductA createProductA(){
        return new ProductA1("ProductA1");
    }
    AbstractProductB createProductB(){
        return new ProductB1("ProductB1");
    }
}

class ConcreteFactory2 extends AbstractFactory{
    AbstractProductA createProductA(){
        return new ProductA2("ProductA2");
    }
    AbstractProductB createProductB(){
        return new ProductB2("ProductB2");
    }
}

//Factory creator - an indirect way of instantiating the factories
class FactoryMaker{
    private static AbstractFactory pf=null;
    static AbstractFactory getFactory(String choice){
        if(choice.equals("a")){
            pf=new ConcreteFactory1();
        }else if(choice.equals("b")){
                pf=new ConcreteFactory2();
            } return pf;
    }
}

// Client
public class Client{
    public static void main(String args[]){
        AbstractFactory pf=FactoryMaker.getFactory("a");
        AbstractProductA product=pf.createProductA();
        //more function calls on product
    }
}

总结:
  抽象工厂模式的实质是“提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类。”
  抽象工厂模式的目的,是将若干抽象产品的接口与不同主题产品的具体实现分离开。这样就能在增加新的具体工厂的时候,不用修改引用抽象工厂的客户端代码。
  抽象工厂模式主要分为四部分:
  AbstractFactory:工厂类的公共接口
  ConcreteFactory:具体工厂
  AbstractProduct:产品类的公共接口
  Product:具体工厂创建的产品实例

适用性:
  在以下情况可以考虑使用抽象工厂模式:
  一个系统要独立于它的产品的创建、组合和表示时。
  一个系统要由多个产品系列中的一个来配置时。
  需要强调一系列相关的产品对象的设计以便进行联合使用时。
  提供一个产品类库,而只想显示它们的接口而不是实现时。
优点:
  具体产品从客户代码中被分离出来
  容易改变产品的系列
  将一个系列的产品族统一到一起创建
缺点:
  在产品族中扩展新的产品是很困难的,要增加一个系列的某一产品,  既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
使用场景:
  QQ 换皮肤,一整套一起换。
  生成不同操作系统的程序。

参考:
https://zh.wikipedia.org/wiki/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F_(%E8%AE%A1%E7%AE%97%E6%9C%BA)
https://zh.wikipedia.org/wiki/%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95
http://baike.baidu.com/view/1580263.htm
http://www.oodesign.com/
https://zh.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82
http://baike.baidu.com/view/1580269.htm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

One2zeror

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值