java设计模式学习之工厂模式和抽象工厂模式

1.工厂模式

1.1 介绍
1.1.1 概念
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
1.1.2 生活化
比如我们去超市买东西,作为顾客,我们不需要关注商品从何而来,只要是超市上架有货,我们就可以购买,这里的超市就相当于一个工厂模式中的工厂,用来管理商品。
1.1.3 优缺点
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。
注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
1.2.代码化
1.2.1 普通工厂模式
首先创建商品的共同接口:

package com.tl.skyLine.pattern.FactoryPattern;

/**
 * Created by tl on 17/3/8.
 * 商品共同接口
 */
public interface Product {
    //每一个商品都有说明介绍
    public void explain();
}

其次,创建商品实现类,香皂Soap和洗头膏Shampoo:

package com.tl.skyLine.pattern.FactoryPattern;

/**
 * Created by tl on 17/3/8.
 */
public class Soap implements Product {
    @Override
    public void explain() {
        System.out.println("我是舒肤佳牌香皂!");
    }
}
package com.tl.skyLine.pattern.FactoryPattern;

/**
 * Created by tl on 17/3/8.
 */
public class Shampoo implements Product {
    @Override
    public void explain() {
        System.out.println("我是海飞丝牌洗头膏!");
    }
}

最后,建工厂类,也就是超市:

package com.tl.skyLine.pattern.FactoryPattern;

/**
 * Created by tl on 17/3/8.
 */
public class Supermarket {

    public Product sell(String name) {
        if ("soap".equals(name)) {
            return new Soap();
        } else if ("shampoo".equals(name)) {
            return new Shampoo();
        } else {
            System.out.println("该商品本商店暂时未上架!");
            return null;
        }
    }
}

我们来测试一下:

package com.tl.skyLine.pattern.FactoryPattern;

/**
 * Created by tl on 17/3/8.
 */
public class FactoryTest {
    public static void main(String[] args) {
        Supermarket market = new Supermarket();
        Product sender = market.sell("soap");
        sender.explain();
    }
}

输出:我是舒肤佳牌香皂!
1.2.2 多个工厂方法模式
是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
我们修一下超市类:

public class Supermarket {

    public Product sellSoap() {
        return new Soap();
    }

    public Product sellShampoo() {
        return new Shampoo();
    }
}

测试类如下:

public class FactoryTest {
    public static void main(String[] args) {
        Supermarket market = new Supermarket();
        Product sender = market.sellSoap();
        sender.explain();
    }
}

输出:我是舒肤佳牌香皂!
1.2.3 静态工厂方法模式
将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

public class Supermarket {

    public static Product sellSoap() {
        return new Soap();
    }

    public static Product sellShampoo() {
        return new Shampoo();
    }
}
public class FactoryTest {
    public static void main(String[] args) {
        Product sender = Supermarket.sellSoap();
        sender.explain();
    }
}

输出:我是舒肤佳牌香皂!
总结:当有大量拥有共同接口(属性)的对象(商品)时,我们可以可以通过工厂方法模式(超市)进行创建,在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。

2.抽象工厂模式

2.1 介绍
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。
2.2 生活化
假如所有的超市只卖一种商品,比如A超市只卖香皂,B超市只卖洗头膏,如果我们想去买洗面奶,怎么办呢,那就只能找一家只卖洗面奶的超市C才可以,所有抽象工厂模式就是把卖商品的超市抽取公共接口,也就是的所谓的工厂工厂。
2.3 代码化
香皂Soap和洗头膏Shampoo实例不变,创建超市抽象接口:

package com.tl.skyLine.pattern.FactoryPattern;

/**
 * Created by tl on 17/3/8.
 */
public interface SuperMarket {
    public Product sell();
}

卖香皂的超市:

package com.tl.skyLine.pattern.FactoryPattern;

/**
 * Created by tl on 17/3/8.
 */
public class SoapMarket implements SuperMarket {

    @Override
    public Product sell() {
        return new Soap();
    }
}

卖洗头膏的超市:

package com.tl.skyLine.pattern.FactoryPattern;

/**
 * Created by tl on 17/3/8.
 */
public class ShampooMarket implements SuperMarket {

    @Override
    public Product sell() {
        return new Shampoo();
    }
}

测试:

public class FactoryTest {
    public static void main(String[] args) {
        SuperMarket market = new SoapMarket();
        Product product = market.sell();
        product.explain();
    }
}

这样,我们扩展商品种类的时候就不需要修改封装好的超市接口,通过新开超市去卖新的商品即可!(此处仅是根据设计模式开闭原则假设的生活例子)

3. 区别

工厂方法模式与抽象工厂模式最大的区别在于,在工厂方法模式中,工厂创造的是一个产品(就是代码中的超市类),而在抽象工厂模式中,工厂创造的是一个产品族(就是代码中的超市类的接口)。

发布了125 篇原创文章 · 获赞 278 · 访问量 116万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览