工厂模式(简单工厂、工厂方法、抽象工厂)

简单工厂

为什么要用工厂模式?
因为,基于面向接口编程的思想,程序开发者,往往只会向程序的使用者提供接口,这个接口,是指广泛意义上的接口,就是开发者提供给你的入口,不单单指Java中的接口。因此,我们在开发时,用到的各种jar包,其实就是class文件,我们往往是拿不到源代码的,也不能修改源代码,因此,我们是不直到源代码的实现细节的。
就像下面的代码,分割线以上,是开发者提供给你的接口及具体实现,分割线以下,是使用者,使用者使用时,是不能直接new开发者的Hamburger对象的,首先,使用者就应该不知道具体实现细节,其次,如果Hamburger改成Hamburger2的话,使用者拿到的是class文件,肯定不知道,就会报错。说白了,就是会违反迪米特原则:不能知道别人内部实现细节。

interface Food{
    void eat();
}

class Hamburger implements Food{

    @Override
    public void eat() {
        System.out.println("吃汉堡");
    }
}
//===============================================================================
public class Test {

    public static void main(String[] args) {

        Food f =new Hamburger();
        f.eat();

    }

因此,引出了简单工程模式,就是用来解决上述问题的。
此时,使用者只需要通过调用工厂方法,然后输入1或者2就行了,此时,就算源代码修改实现类的名字,工厂内的名字会改变,但是,工厂类也是在源代码中的,因此,对使用者来说,看不到改变,不违反迪米特法则。
简单工厂缺点:
如果变化来了,需要扩展产品时,就必须要修改工厂中代码,这样便违反了开闭原则。比如,简单工厂和几个实现类都是前人写好的,然后那人跑路了,现在工作交给你了,现在需要你添加几个新food,基于开闭原则,你是不应该修改前人的工厂代码的。更或者,你手中只有class文件,没有前人的工厂代码,添加新功能,必须修改工厂细节,简单工厂就不行了。

interface Food{
    void eat();
}

class Hamburger implements Food{
    @Override
    public void eat() {
        System.out.println("吃汉堡");
    }
}

class Noodle implements Food{
    @Override
    public void eat() {
        System.out.println("吃面条");
    }
}

class FoodFactory{
    public static Food getFood(int n){
        switch (n){
            case 1:
                return new Hamburger();
            case 2:
                return new Noodle();
        }
        return null;
    }
}


//===============================================================================
public class Test {

    public static void main(String[] args) {

        Food f =FoodFactory.getFood(2);
        f.eat();

    }

工厂方法

简单工厂解决了使用者能直接操作具体实现对象,违反迪米特法则的问题。但是,带来的问题的,工厂类本身需要频繁修改,如果工厂是class文件呢?违反开闭原则。那么,工厂类其实也就不能直接写死,对吧?因此,我们把工厂类写成一个接口,每次需要添加功能时,添加一个实现类,同时,可以再添加一个工厂实现类,就解决了。
个人疑问:
那么,工厂方法是不是又犯了和不适用工厂时一样的错误呢?我们不能知道开发者提供的具体实现类,直接new就违反迪米特法则了。那么,我们在这里直接new工厂的实现类,不也是一样的嘛?照样违反迪米特法则。
其实,确实是这么回事,不过,目的不同,具体实现类,是封装后不希望使用者知道细节的,但是,工厂的实现类,是希望使用者去了解使用的,因此,目的不同,开发者会主动提供工厂实现类来给使用者使用,此时,开发者提供的内容,其实就是广义接口的含义,因此,此时的工厂实现类,属于开发者主动提供的,属于接口,因此,不是使用者私自调用的,不违法迪米特法则。
缺点:
如果有多个产品等级,那么类的数量就会爆炸增长。多一个产品,就会多一个工厂接口及其各种实现类工厂。比如,食物需要食物工厂,饮料需要饮料工厂,再多别的,就需要别的其他工厂,到处都是工厂。

interface Food{
    void eat();
}

class Hamburger implements Food{

    @Override
    public void eat() {
        System.out.println("吃汉堡");
    }
}

class Noodle implements Food{

    @Override
    public void eat() {
        System.out.println("吃面条");
    }
}

interface FoodFactory{
    public Food getFood();
}

class HamburgerFactory implements  FoodFactory{

    @Override
    public Food getFood() {
        return new Hamburger();
    }
}


//===============================================================================
public class Test {

    public static void main(String[] args) {

        Food f =new HamburgerFactory().getFood();
        f.eat();

    }

抽象工厂

如果有多个产品等级,那么工厂方法类的数量就会爆炸增长。因此,用抽象工厂解决这个问题。
工厂方法相当于,把一个产品等级抽象成一个具体类别,也就是说,工厂方法的接口其实还是代表某一个工厂的,食物工厂的接口,就只能生成食物。
而抽象工厂的思想,就是工厂生产的内容,其实是可以自己随便组合的,工厂方法规定某种工厂只能生产某种类型,是自己把路走窄了。因此,抽象工厂相当于,就是抽象出一个组合关系,然后,抽象工厂的实现类中,就可以自由组合各种生成类型,本例中,就是可以组合食物接口和饮料接口。相当于,总的抽象工厂就是个组合框架,框架中写组合什么功能的接口,然后,抽象工厂的具体实现中写各个接口的具体实现。
缺点:
当产品等级发生变化时,都要引起以前工厂的修改。比如,此题中,如果多一个产品等级,目前生成食物和饮料,如果突然多一个生产水果,就需要修改抽象工厂了,需要多加一个水果的接口。

interface Food{
    void eat();
}
interface Drink{
    void drink();
}

class Cola implements Drink{

    @Override
    public void drink() {
        System.out.println("喝可乐");
    }
}

class Hamburger implements Food{

    @Override
    public void eat() {
        System.out.println("吃汉堡");
    }
}

class Noodle implements Food{

    @Override
    public void eat() {
        System.out.println("吃面条");
    }
}

interface Factory{
    public Food getFood();
    public Drink getDrink();
}


class FoodFactory implements  Factory{

    @Override
    public Food getFood() {
        return new Hamburger();
    }

    @Override
    public Drink getDrink() {
        return new Cola();
    }

}


//===============================================================================
public class Test {

    public static void main(String[] args) {

        Food f =new FoodFactory().getFood();
        f.eat();
        Drink d =new FoodFactory().getDrink();
        d.drink();

    }

总结

相当于,工厂方法中,多一个产品等级,多一个水果工厂,就是多写一个接口的问题,但是没办法自由组合。而抽象工厂,就是随便组合,比如,生产食物,或者食物和饮料都生成,都行,但是,如果此时多一个产品等级水果,之前的组合可能就需要改动了,此时,就违反开闭原则了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值