设计模式3,简单工厂、普通工厂、抽象工厂

目录

简单工厂模式

工厂模式

抽象工厂


简单工厂模式

由一个工厂对象决定创建出哪一种产品类的实例。工厂对象根据入参来决定返回哪一种对象。

类型:创建型,但不属于GOF23种设计模式。简单工厂更像是一种编码风格或是习惯。

使用场景:工厂类负责创建的对象比较少。客户端(应用层)只知道传入工厂类的参数,不关心创建对象的逻辑。

优点:只需要传入一个正确的参数,就可以获取你所需要的对象,无须知道其创建细节。

缺点:工厂类的职责相对过重,在增加新的产品类的时候,需要修改工厂类的判断逻辑,违背开闭原则。

例子:

package com.haozi.design.pattern.creational.simplefactory.dto;

public abstract class Game {
    public abstract void buy();
}
package com.haozi.design.pattern.creational.simplefactory.dto;

public class PCGame extends Game{
    @Override
    public void buy() {
        System.out.println("从stream上买游戏");
    }
}
package com.haozi.design.pattern.creational.simplefactory.dto;

public class PS4Game extends Game {
    @Override
    public void buy() {
        System.out.println("从ps store上买游戏");
    }
}
package com.haozi.design.pattern.creational.simplefactory;

import com.haozi.design.pattern.creational.simplefactory.dto.Game;
import com.haozi.design.pattern.creational.simplefactory.dto.PCGame;

public class Test {
    public static void main(String[] args) {
        Game game = new PCGame();
        game.buy();
    }
}

上面这种方式,应用层直接创建对象,对于结构来说,这种做法比较不管是后期扩展还是结构都不好,用简单工厂模式改一下:

package com.haozi.design.pattern.creational.simplefactory;

public class GameFactory {
    public Game getGame(String type){
        if ("pc".equalsIgnoreCase(type)){
            return new PCGame();
        }else if("ps4".equalsIgnoreCase(type)){
            return new PS4Game();
        }
        return null;
    }
}
package com.haozi.design.pattern.creational.simplefactory;

public class Test {
    public static void main(String[] args) {
        Game game = new PCGame();
        game.buy();
        game = new PS4Game();
        game.buy();
    }
}

这样,应用层直接和工厂类打交道,不需要创建具体细节,当然开始的时候也说了,这种结构如果想扩展一个game,需要在工厂类中加判断,这样的方式也不符合开闭原则,所以还可以用反射的方式改进:

public class GameFactory {
    public Game getGame(Class c){
        Game game = null;
        try {
            game = (Game) Class.forName(c.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return game;
    }
}
public class Test {
    public static void main(String[] args) {
        GameFactory gameFactory = new GameFactory();
        Game game = gameFactory.getGame(PCGame.class);
        if (game != null){
            game.buy();
        }
    }
}

这样,再进行扩展的时候就不需要再修改工厂类了,当然,这种做法也不是非常完美的。 

用到设计模式的源码:

不需要太多解释了,这里只提一点,方法用的是static,是因为这里不需要进行扩展了。


工厂模式

定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个对象,工厂模式让对象的实例化推迟到子类中进行。

类型:创建型

使用场景:创建对象需要大量重复的代码,客户端(应用层)不依赖于产品类如何被创建、实现等细节。一个类通过其子类来决定创建哪个对象

优点:用户只需要关心所需产品对应的工厂,无需关心创建细节。加入新产品符合开闭原则,提高扩展性。

缺点:类的个数容易过多,增加复杂度。增加了系统的抽象性和理解难度。

例子:

public abstract class Game {
    public abstract void buy();
}
public class PCGame extends Game {
    @Override
    public void buy() {
        System.out.println("从stream上买游戏");
    }
}
public class PS4Game extends Game {
    @Override
    public void buy() {
        System.out.println("从ps store上买游戏");
    }
}
public interface GameFactory {
    Game getGame();
}
public class PCGameFactory implements GameFactory {
    @Override
    public Game getGame() {
        return new PCGame();
    }
}
public class PS4GameFactory implements GameFactory {
    @Override
    public Game getGame() {
        return new PS4Game();
    }
}
public class Test {
    public static void main(String[] args) {
        GameFactory factory = new PCGameFactory();
        Game game = factory.getGame();
        game.buy();
    }
}

这样,应用层test直接和gamefactory打交道,具体创建什么实例直接用对应的factory就好,从扩展性来说,新加一个游戏,加一个对应的GameFactory和一个对应的Game实现类,扩展性好,但加的东西有点多。

用到设计模式的源码:

Collection中

通过查找实现类可以找到ArrayList

根据工厂方法的类图,我画了一个简单的

 再看一个:

URLStreamHandlerFactory

找一下实现类

 可以看出实现关系,他们的返回值URLStreamHandler也有很多实现类


抽象工厂

抽象工厂提供了一个创建一系列相关或相互依赖对象的接口,无需指定他们具体的类。抽象工厂可以把具有同一主题的工厂封装起来,客户端程序创建抽象工厂的具体实现,然后使用抽象工厂的实现来创建接口工厂,客户端不需要知道使用的具体工厂的类型。

类型:创建型

使用场景:客户端(应用层)不依赖于产品类如何被创建、实现等细节。强调一系列相关的产品对象(同一产品族)一起使用创建对象需要大量重复的代码。提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

关于产品族和产品等级:

举个例子,美的有空调、洗衣机、冰箱,海尔也有空调、洗衣机、冰箱。

产品族:美的空调、美的洗衣机、美的冰箱都属于美的,是同一个产品族。

产品等级:美的空调、海尔空调都是空调,属于一个产品等级结构。

优点:具体产品在应用层代码隔离,无需关心创建细节。将一个系列的产品族统一到一起创建。

缺点:规定了所有可能被创建的产品集合,产品族中扩展新的产品比较困难,需要修改抽象工厂的接口。增加了系统的抽象性和理解难度。

例子:

上面的游戏的例子,游戏可以分为电脑游戏和ps4游戏等,现在需要新加一个需求,电脑和ps4不光有游戏,还要有别的软件例如播放器,那以上面工厂方法的例子,还需要新建播放器工厂、电脑播放器、ps4播放器等,这种情况下,用抽象工厂来试试:

public interface SoftwareFactory {
    Game initGame();
    MusicPlayer initMusicPlayer();
}
public abstract class Game {
    public abstract void play();
}
public abstract class MusicPlayer {
    public abstract void play();
}
public class PCGame extends Game {
    @Override
    public void play() {
        System.out.println("玩电脑游戏");
    }
}
public class PS4Game extends Game {
    @Override
    public void play() {
        System.out.println("玩PS4游戏");
    }
}
public class PCMusicPlayer extends MusicPlayer {
    @Override
    public void play() {
        System.out.println("听电脑播放器的歌");
    }
}
public class PS4MusicPlayer extends MusicPlayer {
    @Override
    public void play() {
        System.out.println("听PS4的歌");
    }
}
public class PCSoftwareFactory implements SoftwareFactory {
    @Override
    public Game initGame() {
        return new PCGame();
    }

    @Override
    public MusicPlayer initMusicPlayer() {
        return new PCMusicPlayer();
    }
}
public class PS4SoftwareFactory implements SoftwareFactory {
    @Override
    public Game initGame() {
        return new PS4Game();
    }

    @Override
    public MusicPlayer initMusicPlayer() {
        return new PS4MusicPlayer();
    }
}
public class Test {
    public static void main(String[] args) {
        SoftwareFactory softwareFactory = new PCSoftwareFactory();
        Game game = softwareFactory.initGame();
        MusicPlayer musicPlayer = softwareFactory.initMusicPlayer();
        game.play();
        musicPlayer.play();

        SoftwareFactory softwareFactory1 = new PS4SoftwareFactory();
        Game game1 = softwareFactory1.initGame();
        MusicPlayer musicPlayer1 = softwareFactory1.initMusicPlayer();
        game1.play();
        musicPlayer1.play();
    }
}

 

 在产品族产品很多的情况下,用抽象工厂是非常合适的,因为如果用普通工厂,人为的编码不排除出现PCGame和PS4MusicPlayer组合的可能性,而用抽象工厂,应用层直接和SoftwareFactory打交道,不直接和应用打交道,只需要知道是哪种类型的就好。所以如果我需要新增一个产品族,那么我新建对应的软件工厂和具体实现就好,非常方便。但是,当然缺点也一目了然,这种模式下新建一个产品等级,比如新建一个其他软件,那修改的地方可就非常多了。

所以总结一下,抽象工厂关注产品族,工厂模式关注产品等级结构。

用到设计模式的源码:

Connection中

从这三个方法可以看出,返回的都是同一个产品族,比如创建一个mysql的connection,那么返回的肯定都是mysql的statement。

再看Statement

这也是一个抽象工厂,再比如

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值