1. 工厂模式
定义:定义一个创建产品对象的工厂接口,将对象的创建工作推迟到具体子工厂类当中,使其满足创建与使用相分离这一特点。
1.1 简单工厂模式
1.1.1 问题背景分析
现实生活中,原始社会自给自足(没有工厂),农耕社会小作坊(简单工厂,民间酒坊),工业革命流水线(工厂方法,自产自销),现代产业链代工厂(抽象工厂,富士康)。我们的项目代码同样是由简到繁一步一步迭代而来的,但对于调用者来说,却越来越简单。
在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式来代替。
1.1.2 定义
包含一个抽象产品、多个具体产品以及一个具体工厂类,工厂类用于创建产品对象,每次新增产品后,都需要修改工厂类,不符合开闭原则。
1.1.3 类图
- 主要角色:
- 简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
- 抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
- 具体产品(ConcreteProduct):是简单工厂模式的创建目标。
1.1.3 代码
public class Client {
public static void main(String[] args) {
}
//抽象产品
public interface Product {
void show();
}
//具体产品:ProductA
static class ConcreteProduct1 implements Product {
public void show() {
System.out.println("具体产品1显示...");
}
}
//具体产品:ProductB
static class ConcreteProduct2 implements Product {
public void show() {
System.out.println("具体产品2显示...");
}
}
final class Const {
static final int PRODUCT_A = 0;
static final int PRODUCT_B = 1;
static final int PRODUCT_C = 2;
}
static class SimpleFactory {
public static Product makeProduct(int kind) {
switch (kind) {
case Const.PRODUCT_A:
return new ConcreteProduct1();
case Const.PRODUCT_B:
return new ConcreteProduct2();
}
return null;
}
}
}
1.2 工厂方法模式
1.2.1 定义
是简单工厂模式的进一步抽象化,可以再不修改源代码的前提下引进新的产品,即符合开闭原则。
1.2.2 使用场景
- 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
- 客户不关心创建产品的细节,只关心产品的品牌
1.2.3 类图
- 主要角色:
- 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
1.2.4 具体代码
public interface AbstractFactory{
Product newProduct();
}
// 具体工厂创建对应具体+
public class ConcreteFactory1 implements AbstractFactory{
public Product newProduct(){
System.out.println("我是具体工厂1");
Return new ConcreteProduct1();
}
}
public class ConcreteFactory2 implements AbstractFactory{
public Product newProduct(){
System.out.println("我是具体工厂2");
Return new ConcreteProduct2();
}
}
public interface Product{
void show();
}
public class ConcreteProduct1 implements Product{
public void show(){
System.out.println("我是产品1");
}
}
public class ConcreteProduct2 implements Product{
public void show(){
System.out.println("我是产品2");
}
}
public class AbstractFactoryTest {
public static void main(String[] args) {
AbstractFactory fa1 = new ConcreteFactory1();
fa1.newProduct().show();
AbstractFactory fa2 = new ConcreteFactory1();
fa2.newProduct().show();
}
}
1.3 抽象工厂模式
工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。
抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族。
1.3.1 定义
抽象工厂模式是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
1.3.2 类图
主要角色:
- 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
- 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
抽象工厂模式同工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品等 4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同。
-
当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
-
当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。
1.3.3 具体代码
public interface AbstractFactory{
public Product newProduct1();
public Product newProduct2();
}
public class ConcreteFactory1 implements AbstractFactory{
public Product newProduct1(){
System.out.println("我是生产产品1的,具体工厂1");
Return new ConcreteProduct11();
}
public Product newProduct2(){
System.out.println("我是生产产品2的,具体工厂1");
Return new ConcreteProduct21();
}
}
public class ConcreteFactory2 implements AbstractFactory{
public Product newProduct1(){
System.out.println("我是生产产品1的,具体工厂2");
Return new ConcreteProduct12();
}
public Product newProduct2(){
System.out.println("我是生产产品2的,具体工厂2");
Return new ConcreteProduct22();
}
}
public interface Product1{
void show();
}
public interface Product2{
void show();
}
public class ConcreteProduct11 implements Product1{
public void show(){
System.out.println("我是产品11");
}
}
public class ConcreteProduct12 implements Product1{
public void show(){
System.out.println("我是产品12");
}
}
public class ConcreteProduct21 implements Product2{
public void show(){
System.out.println("我是产品11");
}
}
public class ConcreteProduct22 implements Product2{
public void show(){
System.out.println("我是产品12");
}
}
2. 单例模式
2.1 定义
指一个类只有一个实例,且该类能自行创建这个实例的一种模式。
特点:
- 单例类只有一个实例对象;
- 该单例对象必须由单例类自行创建;
- 单例类对外提供一个访问该单例的全局访问点。
2.2 单例模式应用场景
- 需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 GC。
- 某类只要求生成一个对象的时候。
- 某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
- 某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
- 频繁访问数据库或文件的对象。
- 对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。
- 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。
2.3 结构与实现
思路:将类的构造函数私有化,自身具有一个静态的私有实例,通过一个静态的公有函数来创建和获取该静态私有实例。
主要角色:
- 单例类:包含一个实例且能自行创建这个实例的类。
- 访问类:使用单例的类。
2.3.1 懒汉式单例(课本中为懒汉式)
public class LazySingleton{
// 懒汉式,在程序初始时不创建对象,只有在被调用时才创建
private static volatile LazySingleton instance = null;
private LacySingleton(){}
public static synchronized LacySingleton getInstance(){
if(instance==null){
instance = new LazySingleton();
}
return instance;
}
}
如果编写的是多线程程序,则不要删除上例代码中的关键字 volatile 和 synchronized,否则将存在线程非安全的问题。如果不删除这两个关键字就能保证线程安全。
缺点:
每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。
2.3.2 饿汉式单例
- 关键字static作用:
-
为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。
-
实现某个方法或属性与类而不是对象关联在一起
具体而言,在Java语言中,static主要有4中使用情况:成员变量、成员方法、代码块和内部类
public class HungrySingleton{
// 程序一运行就创建对象,被调用时直接返回
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
空间,而与创建对象的个数无关。
- 实现某个方法或属性与类而不是对象关联在一起
具体而言,在Java语言中,static主要有4中使用情况:成员变量、成员方法、代码块和内部类
public class HungrySingleton{
// 程序一运行就创建对象,被调用时直接返回
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。