Java ------ 工厂模式、单例模式
工厂模式
简单工厂模式:
1.创建Car接口
- public interface Car {
- public void drive();
- }
2.创建两个实体类,分别实现Car接口
- public class Benz implements Car {
- @Override
- public void drive() {
- System.out.println("Driving Benz");
- }
- }
- public class Bmw implements Car {
- @Override
- public void drive() {
- System.out.println("Driving Bmw");
- }
- }
3.创建Driver工厂,根据传过来的值创建不同的对象
- public class DriverFactory {
- public Car drivercar(String key){
- if("Benz".equals(key)){
- return new Benz();
- }else if("Bwm".equals(key)){
- return new Bmw();
- }
- return null;
- }
- }
4.测试
- public class TestFactory {
- @Test
- public void test() {
- DriverFactory dirver = new DriverFactory();
- Car car1= dirver.drivercar("Bwm");
- car1.drive();
- Car car2 = dirver.drivercar("Benz");
- car2.drive();
- }
- }
工厂方法模式:
包括:
1.抽象产品:产品对象同一的基类,或者是同一的接口。
2.具体的产品:各个不同的实例对象类
3.抽象工厂:所有的子类工厂类的基类,或是同一的接口
4.具体的工厂子类:负责每个不同的产品对象的实际创建
工厂方法的优缺点
工厂方法模式的优点:
(1)在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名。
(2)基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,正是因为所有的具体工厂类都具有同一抽象父类。
(3)使用工厂方法模式的另一个优点是在系统中加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
工厂方法模式的缺点如下:
(1)在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
(2)由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
工厂方法模式的适用环境
在以下情况下可以使用工厂方法模式:
(1)一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
(2)一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
(3)将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
步骤:
1.抽象的产品类
- public interface TV {
- public void play();
- }
2.具体的产品类
- public class HaierTV implements TV {
- @Override
- public void play() {
- System.out.println("海尔电视播放中.....");
- }
- }
- public class XimiTV implements TV {
- @Override
- public void play() {
- System.out.println("小米电视播放中.....");
- }
- }
3.抽象的工厂类
- public interface TVFactory {
- public TV productTV();
- }
4.具体的工厂类
- public class HaierTVFactory implements TVFactory {
- @Override
- public TV productTV() {
- System.out.println("海尔电视工厂生产海尔电视.....");
- return new HaierTV();
- }
- }
- public class XimiTVFactory implements TVFactory {
- @Override
- public TV productTV() {
- System.out.println("小米电视工厂生产海尔电视.....");
- return new XimiTV();
- }
- }
5.测试
- public class TestFactory {
- @Test
- public void test(){
- TVFactory tvf1 = new HaierTVFactory();
- TV tv1 = tvf1.productTV();
- tv1.play();
- TVFactory tvf2 = new XimiTVFactory();
- TV tv2 = tvf2.productTV();
- tv2.play();
- }
- }
抽象工厂模式:
当每个抽象产品都有多于一个的具体子类的时候(乘车工具有两种、早餐有两种),工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产品角色都有两个具体产品(人有穷人和富人)。抽象工厂模式提供两个具体工厂角色(穷人工厂和富人工厂),分别对应于这两个具体产品角色(穷人骑自行车和橙汁;富人坐公交喝牛奶),每一个具体工厂角色只负责某一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。
1.抽象产品接口:定义产品的接口,公共的暴露方法。便于实际的产品类实现。
2.具体的产品类:包含实际产品的类的逻辑处理:
3.抽象工厂接口:定义产生系列对象的接口
4.具体的工厂实现:实现抽象的接口工厂,返回具体的产品类的实现。
步骤:
1.抽象的产品接口
- public interface Car {
- public void gotowork();
- }
- public interface BreakFast {
- public void eat();
- }
2.具体的产品类
1)Car
- public class Bike implements Car {
- @Override
- public void gotowork() {
- System.out.println("骑自行车去工作....");
- }
- }
- public class Bus implements Car {
- @Override
- public void gotowork() {
- System.out.println("坐公交去工作....");
- }
- }
2)BreakFast类
- public class Milk implements BreakFast {
- @Override
- public void eat() {
- System.out.println("早餐喝牛奶.....");
- }
- }
- public class Orange implements BreakFast {
- @Override
- public void eat() {
- System.out.println("早餐喝橙汁.....");
- }
- }
3.抽象的工厂类
- public interface AbstractFactory {
- public Car getcar();
- public BreakFast getbreakfast();
- }
4.具体的工厂类
- public class LowPersonFactory implements AbstractFactory {
- @Override
- public Car getcar() {
- return new Bike();
- }
- @Override
- public BreakFast getbreakfast() {
- return new Orange();
- }
- }
- public class HighPersonFactory implements AbstractFactory {
- @Override
- public Car getcar() {
- return new Bus();
- }
- @Override
- public BreakFast getbreakfast() {
- return new Milk();
- }
- }
5.测试
- public class TestFactory {
- @Test
- public void test3(){
- AbstractFactory lowfactory = new LowPersonFactory();
- Car car = lowfactory.getcar();
- BreakFast breakFast = lowfactory.getbreakfast();
- System.out.println("早饭:");
- breakFast.eat();
- System.out.println("上班交通工具是:");
- car.gotowork();
- AbstractFactory highfactory = new HighPersonFactory();
- Car car2 = highfactory.getcar();
- BreakFast getbreakfast2 = highfactory.getbreakfast();
- System.out.println("早饭:");
- getbreakfast2.eat();
- System.out.println("上班交通工具是:");
- car2.gotowork();
- }
- }
单例模式:
主要介绍:懒汉式单例、饿汉式单例
特点:
1.单例类只能有一个实例
2.单例类必须自己创建自己的唯一实例
3.单例类必须给所有其他的对象提供这一实例
1、饿汉式单例
- public class Singleton{
- private static Singleton instance = new Singleton();
- private Singleton(){}
- public static Singleton newInstance(){
- return instance;
- }
- }
从代码中我们看到,类的构造函数定义为private的,保证其他类不能实例化此类,然后提供了一个静态实例并返回给调用者。
饿汉模式是最简单的一种实现方式,饿汉模式在类加载的时候就对实例进行创建,实例在整个程序周期都存在。
它的好处是只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免了多线程同步的问题。它的缺点也很明显,即使这个单例没有用到也会被创建,而且在类加载之后就被创建,内存就被浪费了。
这种实现方式适合单例占用内存比较小,在初始化时就会被用到的情况。但是,如果单例占用的内存比较大,或单例只是在某个特定场景下才会用到,使用饿汉模式就不合适了,这时候就需要用到懒汉模式进行延迟加载。
2、懒汉式单例
- public class Singleton{
- private static Singleton instance = null;
- private Singleton(){}
- public static Singleton newInstance(){
- if(null == instance){
- instance = new Singleton();
- }
- return instance;
- }
- }
懒汉模式中单例是在需要的时候才去创建的,如果单例已经创建,再次调用获取接口将不会重新创建新的对象,而是直接返回之前创建的对象。
如果某个单例使用的次数少,并且创建单例消耗的资源较多,那么就需要实现单例的按需创建,这个时候使用懒汉模式就是一个不错的选择。
但是这里的懒汉模式并没有考虑线程安全问题,在多个线程可能会并发调用它的getInstance()方法,导致创建多个实例,因此需要加锁解决线程同步问题,实现如下。
- public class Singleton{
- private static Singleton instance = null;
- private Singleton(){}
- public static synchronized Singleton newInstance(){
- if(null == instance){
- instance = new Singleton();
- }
- return instance;
- }
- }
3、双重校验锁
加锁的懒汉模式看起来即解决了线程并发问题,又实现了延迟加载,然而它存在着性能问题,依然不够完美。synchronized修饰的同步方法比一般方法要慢很多,如果多次调用getInstance(),累积的性能损耗就比较大了。因此就有了双重校验锁,先看下它的实现代码
- public class Singleton {
- private static Singleton instance = null;
- private Singleton(){}
- public static Singleton getInstance() {
- if (instance == null) {
- synchronized (Singleton.class) {
- if (instance == null) {
- instance = new Singleton();
- }
- }
- }
- return instance;
- }
- }
可以看到上面在同步代码块外多了一层instance为空的判断。由于单例对象只需要创建一次,如果后面再次调用getInstance()只需要直接返回单例对象。因此,大部分情况下,调用getInstance()都不会执行到同步代码块,从而提高了程序性能。不过还需要考虑一种情况,假如两个线程A、B,A执行了if (instance == null)语句,它会认为单例对象没有创建,此时线程切到B也执行了同样的语句,B也认为单例对象没有创建,然后两个线程依次执行同步代码块,并分别创建了一个单例对象。为了解决这个问题,还需要在同步代码块中增加if (instance == null)语句,也就是上面看到的代码
Java ------ 工厂模式、单例模式的更多相关文章
- java工厂模式
(1)概念大白话:java工厂模式就是客户端(main函数)要创建对象觉得麻烦就让另外一个叫工厂的类帮它创建,然后自己每次要创建对象就叫工厂帮它弄,举个例子,在没有工厂这个"手下" ...
- Java工厂模式解耦 —— 理解Spring IOC
Java工厂模式解耦 -- 理解Spring IOC 最近看到一个很好的思想来理解Spring IOC,故记录下来. 资源获取方式 主动式:(要什么资源都自己创建) 被动式:(资源的获取不是我们创建, ...
- 10.Java设计模式 工厂模式,单例模式
Java 之工厂方法和抽象工厂模式 1. 概念 工厂方法:一抽象产品类派生出多个具体产品类:一抽象工厂类派生出多个具体工厂类:每个具体工厂类只能创建一个具体产品类的实例. 即定义一个创建对象的接口(即 ...
- java工厂模式个人体会
上一边文章主要对单例模式做了一个总结,这篇文章主要对工厂模式也写一写个人的体会. 工厂模式是设计模式的一种,它主要是把实现产品对象的过程封装起来,然后提供给客户端相应的接口.工厂模式也是有3种,分别为 ...
- Java学习笔记——Java工厂模式之简单工厂
package com.app; import java.util.Date; /* * 工厂模式:简单工厂.工厂方法.抽象工厂 * * */ public class Test0718_Factor ...
- JAVA - 工厂模式
1. 简单工厂违背OCP(Open Close Principle)原则 , 即对增加开放,对修改关闭.如果要符合OCP原则,要针对接口编程. //简单工厂模式,违反了OCP原则 public cla ...
- Java 工厂模式(一)— 抽象工厂(Abstract Factory)模式
一.抽象工厂模式介绍: 1.什么是抽象工厂模式: 抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的一种形态,抽象工厂模式向客户端提供一个接口,使得客户端在不知道具体产品的情类型的情况下,创建 ...
- Java 工厂模式(一)— 简单工厂模式
一.什么是工厂模式: Java中的工厂模式主要是用来将有大量共同接口的类实例化.工厂模式可以动态的决定将哪一个类实例化,不必事先知道要实例化哪个类,将类的实例化的主动权交给工厂而不是类本身.我们常见的 ...
- java 工厂模式 转载
下面介绍三种设计模式,简单工厂模式,工厂方法模式,抽象工厂模式 思考如下场景: 有一天,林同学准备去买笔记本,他到商城发现有两款电脑他特别喜欢, 一款是 Macbook Pro, 另一款是 Surfa ...
随机推荐
- redis缓存+session 实现单点登录
一.单点登录介绍 单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系 ...
- Zeppelin的安装和SparkSQL使用总结
zeppelin是spark的web版本notebook编辑器,相当于ipython的notebook编辑器. 一Zeppelin安装 (前提是spark已经安装好) 1 下载https://zepp ...
- POJ2828 Buy Tickets 树状数组
Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get ...
- java控制执行流程
控制执行流程 欢迎转载,转载烦请注明出处,谢谢. https://www.cnblogs.com/sx-wuyj/p/11177257.html java当中涉及到的关键字包括if-else.whil ...
- HDU 1276 士兵队列训练问题(队列)
题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=1276 题目: 士兵队列训练问题 Time Limit: 2000/1000 MS (Java/Othe ...
- SpringBoot中如何灵活的实现接口数据的加解密功能?
数据是企业的第四张名片,企业级开发中少不了数据的加密传输,所以本文介绍下SpringBoot中接口数据加密.解密的方式. 本文目录 一.加密方案介绍二.实现原理三.实战四.测试五.踩到的坑 一.加密方 ...
- Apache源码包在LINUX(CENTOS6.8)中的安装(出现问题及解决)
任务:在CENT6.8系统中安装Apache(版本为:httpd-2.4.41) 前提:由于源码包必须先编译后安装,所以必须先安装编译器:gcc 理论步骤: 1.检测gcc软件包,如果不存在则进行安装 ...
- 拨云见日,彻底弄清楚Java日志框架 log4j, logback, slf4j的区别与联系
log4j 以及 logback, slf4j 官网 日志框架的困惑 作为一个正常的项目,是必须有日志框架的存在的,没有日志,很难追踪一些奇奇怪怪的系统问题. 但是,我们经常在项目的依赖中,见到奇奇怪 ...
- 解决tortoiseSvn 访问版本库的时候一直初始化,或者无响应的问题
现象 svn访问版本库时一直提示: please wait while the repository browser is initializing 没有反应,甚至3-4分钟才会出来,即便出来也会很卡 ...
- django-URL之include函数(五)
三种格式:(1)incude(module,namespace=None) from django.urls import path,include from book import urls url ...