谈谈我对工厂模式的理解


多读多写多记录,多学多练多思考。--------- Banana.Banuit Gang(香柚帮)


说起一件事物或者一个东西的时候,我们第一反应就是,这个东西或事物到底是干啥的,有什么用呢?为什么要用它?不用不行吗?它到底能给我们带来什么?等等等等,我们会生出好多好多的疑问。

那么工厂模式到底是个什么玩意儿,有什么作用呢?

工厂模式:其实它主要是用来实例化有共同接口的类,它可以动态的决定应该实例化哪一个类

工厂模式主要分为三种形态:

  1. 简单工厂模式(Simple Factory)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)

简单工厂模式(Simple Factory)

首先我们来说一个这个简单工厂模式(Simple Factory),简单工厂模式又称为静态工厂,它是三种工厂模式中结构最简单的一种形态,简单工厂类中主要有一个静态方法,用来接受参数,并根据参数进行switch或if判断来决定返回实现同一接口的不同类的实例。

比如说:康师傅有一个工厂为简单工厂类,工厂类里边有一个方法,通过康师傅传输过来的字符串指令进行switch判断到底是生产饮料还是生产泡面,而这个饮料和泡面两个类共同实现了一个产品的接口。

//饮料和泡面的共同接口
public interface Product{}
//饮料和泡面实现了Product接口
public class Drinks implements Product {
    public Drinks() {
        system.out.println("生产饮料");
    }
}
public class Noodles implements Product {
    public Noodles() {
        system.out.println("生产泡面");
    }
}
//康师傅的简单工厂类
public class SimpleFactory {
    //根据字符串指令创建相应的对象
    public static Product createProduct(String name) {
        Product product = null;
        switch (name) {
            case "drinks":
                product = new Drinks();
                break;
            case "noodles":
                product = new Noodles();
                break;
        }
        return product;
    }
}

好了,有了上边的简单工厂类和一些产品,康师傅就可以下达生产指令了。

//客户端代码
public class Client {

    public static void main(String[] args) {
        try {  
            SimpleFactory.createProduct("drinks");  
            SimpleFactory.createProduct("noodles");  
        } catch (Exception e) {  
            e.printStackTrace();  
        }
    }

}

由上面的代码可以看出,简单工厂模式的核心就是一个SimpleFactory类

优点:简单工厂类中包含了必要的逻辑判断能力和所有产品的创建权利,它可以根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。这样的话,当产品的类名更换或者增加产品时我们都无需修改客户端代码,只需要在简单工厂类上增加一个分支判断代码即可。使用起来似乎非常的方便。

缺点:没有遵守“开放—封闭”原则。所谓的“开放-封闭”原则就是开放接口,封闭修改。我们每次想要增加一种新产品的时候,都必须修改SimpleFactory的源码。其次,当我们拥有很多很多产品的时候,而且产品之间又存在复杂的层次关系的时候,这个类必须拥有复杂的逻辑判断能力,这会导致这个简单工厂类很庞大臃肿、耦合性高,不利于维护和扩展。而且整个系统严重依赖SimpleFactory类,一旦此类出现问题,则整个系统将会崩溃。

工厂方法模式(Factory Method)

从上边的简单工厂模式我们可以看出产品的生产太依赖于简单工厂这个核心,一旦简单工厂类出现问题,则整个模式都将受到影响,不利于维护和扩展。

工厂方法模式通过把工厂类定义为接口,以多态的形式来削弱工厂类的职能,对简单工厂模式进一步的解耦,这相当于是把原本会因为业务代码而庞大的简单工厂类,拆分成了一个个的工厂类,这样代码就不会都耦合在同一个类里了。大大降低了简单工厂模式的一些风险,提高日后的可维护性和可扩展性。

这就相当于:康师傅现在把简单工厂类改为了一个工厂接口,又建造了两个实现了这个接口的饮料工厂和泡面工厂,饮料工厂生产饮料,泡面工厂生产泡面,分工明确,一个工厂出问题不会影响到另一个工厂的正常运作。

//工厂接口
public interface Factory {
    public Product createProduct();
}
//产品接口
public interface Product{}
//饮料和泡面实现了Product接口
public class Drinks implements Product {
    public Drinks() {
        system.out.println("生产饮料");
    }
}
public class Noodles implements Product {
    public Noodles() {
        system.out.println("生产泡面");
    }
}
//具体工厂类实现了工厂接口
//生产饮料的工厂  
public class DrinksFactory implements Factory{  
    public Product createProduct(){  
          return new Drinks();  
    }  
}  

//生产泡面的工厂  
public class NoodlesFactory implements Factory{  
    public Product createProduct(){  
          return new Noodles();  
    }  
} 
//客户端代码
public class Client {
 
    public static void main(String[] args) throws Exception {
 
        // 使用反射机制实例化工厂对象,因为字符串是可以通过变量改变的
        //反射方法的实质是在对象实例化的时候传引用,将程序由编译时转为运行时,通过字符串变量来处理,去除了switch判断的麻烦
        Factory drinksFactory = (Factory) Class.forName("com.banana.factory.DrinksFactory ").newInstance();
        Factory noodlesFactory = (Factory) Class.forName("com.banana.factory.NoodlesFactory").newInstance();
 
        // 通过工厂对象创建相应的实例对象
        Product drinks = drinksFactory.createProduct();
        Product noodles = noodlesFactory.createProduct();
 
    }

}

从上面创建产品对象的代码可以看出,工厂方法和简单工厂的主要区别是,简单工厂是把创建产品的职能都放在一个类里面,而工厂方法则把不同的产品的创建交给了实现了工厂接口的不同工厂类去创建,这样就算其中一个工厂类出了问题,其他工厂类也能正常工作,互相不受影响,以后增加新产品,也只需要新增一个实现工厂接口工厂类,而不用修改已有代码了。

优点:不同产品的实例对象的创建,没有耦合在同一个工厂类里,实现了对简单工厂模式的解耦,并且遵循了“发放-封闭”原则。

缺点:每增加一个产品类,就需要增加一个对应的工厂类,增加了额外的开发量。

抽象工厂模式(Abstract Factory)

以我的理解,抽象工厂模式和工厂方法模式的区别就在于,在工厂方法模式下一个工厂只能生产同类同品的产品(同一规格的一类产品),而在抽象工厂模式下一个工厂可以生产多类同品的产品(同一规格的多类产品,也可以称作一系列产品)。

比如说,康师傅的工厂,在工厂方法模式下,它只能生产一种规格的饮料或泡面,而在抽象工厂模式下,它可以生产一系列的饮料或泡面,比如普通装、加量装、豪华装等等。其实这个和分类有点类似,也就是工厂方法模式下只能生产普通装或者加量装、豪华装其中的一类产品,而抽象工厂模式下可以生产这一系列不同的产品。

我们可以对饮料和泡面分别创建一个接口

//分别创建不同的产品接口
//饮料接口
public interface Drinks {}

//泡面接口
public interface Noodles {}
//根据产品接口实现具体的产品
//普通装饮料
public class CommonDrinks implements Drinks {
    public CommonDrinks() {
        system.out.println("生产普通装饮料");
    }
}

//加量装饮料
public class BigDrinks implements Drinks {
    public BigDrinks() {
        system.out.println("生产加量装饮料");
    }
}

//普通装泡面
public class CommonNoodles implements Noodles {
    public CommonNoodles() {
        system.out.println("生产普通装泡面");
    }
}

//加量装泡面
public class BigNoodles implements Noodles {
    public BigNoodles() {
        system.out.println("生产加量装泡面");
    }
}

产品准备好了,接下来我们定义工厂接口

public interface Factory {
    public Drinks createDrinks();
    public Noodles createNoodles();
}

接下来创造具体的工厂类,我们根据上面产品的接口,把普通装的产品分为一类,交给一个工厂来管理,把加量装的产品交给另一个工厂管理,根据这个分类,我们可以实现如下的两个具体工厂类 

//生产普通装产品的工厂
public class CommonFactory implements Factory {
    public Drinks createDrinks() {
        return new CommonDrinks();
    }
    public Noodles createNoodles() {
        return new CommonNoodles();
    }
}

//生产加量装产品的工厂
public class BigFactory implements Factory {
    public Drinks createDrinks() {
        return new BigDrinks();
    }
    public Noodles createNoodles() {
        return new BigNoodles();
    }
}
//客户端代码
public class Client {
 
    public static void main(String[] args){
 
        // 只需要确定实例化哪一个对象给factory
        // Factory factory = new CommonFactory();
        Factory factory = new BigFactory();
 
        // 输出生产加量装饮料
        Drinks drinks = factory.createDrinks();
 
        // 输出生产加量装泡面
        Noodlse noodles = factory.createNoodles();
 
 
    }

}

由上面可以看出,在运用上我觉得工厂方法和抽象工厂,都有自己的应用场景,并没有什么优劣之分。

优点:抽象工厂模式易于交换产品系列,由于具体工厂类,在一个应用程序中只需要在初始化的时候出现一次, 这就使得改变一个应用的具体工厂变得非常容易,它只需改变具体工厂即可使用不同的产品配置。它让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中。

缺点:抽象工厂模式虽然便于两系列之间的切换,但是不便于增加需求功能。还有就是,客户端程序肯定不止一个,每次都需要声明 Factory factory = new CommonFactory(), 如果有100个调用产品的类,就需要更改100次Factory factory = new BigFactory()。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值