个人学习笔记分享,当前能力有限,请勿贬低,菜鸟互学,大佬绕道
如有勘误,欢迎指出和讨论,本文后期也会进行修正和补充
前言
单例模式也是Java最简单和常见的模式之一
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象
根据产品类型和抽象成都可分为==简单工厂模式、工厂方法模式和抽象工厂模式==
实际上前面介绍的单例模式,也属于工厂模式。
1.介绍
使用目的:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行
使用时机:需要根据不同场景创建不同的实例
解决问题:创建子类的时候,必须明确知道是哪个类,再调用对应的方法,积少成多后管理和维护极其麻烦
实现方法:子类都是用一个工厂类的一个接口创建,输入不同的条件,然后接口返回对应的子类实例对象
应用实例:
- 管理设备,用户只需要知道设备型号即可,而不需要知道具体的产品名和设备参数
- 策略管理,对于不同的策略,仅仅知道其唯一标识即可获取实例,而不需要知道具体策略是怎样的
优点:
- 一个调用者想创建一个对象,只要知道其名称就可以了
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
- 屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:随着产品越来越多
- 类的数量会越来越多,依然会造成管理困难的问题
- 系统的复杂度和抽象程度越来越高,简单点说就是。。。看不懂了。。。
- 增加了系统具体类的依赖,也就是耦合度增加了,这并不是一件好事情
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式,但因为其缺点的存在,简单对象建议直接new就好了
2.简单工厂模式
2.1.简介
专门定义一个类用来创建其它类的实例,被创建的实例通常都具有共同的父类。调用工厂类的方法,输入必要的信息,输出对应的实例。
包括三个角色
- 抽象产品接口:声明所有产品的公共方法
- 具体产品类:按照自己的需求实现抽象接口的方法
- 工厂:提供公共方法用于按照不同条件生产产品
2.2.实现
-
创建接口,作为标准规范类(AbstractProduct)
public interface Animal { void say(); }
-
创建子类Dog.class,实现接口
public class Dog implements Animal { @Override public void say() { System.out.println("汪!"); } }
-
创建子类Cat.class,实现接口
public class Cat implements Animal { @Override public void say() { System.out.println("喵!"); } }
-
创建工厂类AnimalFactory.class,用于创建实例
public class AnimalFactory { public Animal createAnimal(String name) { Animal animal = null; switch (name) { case "dog": animal = new Dog(); break; case "cat": animal = new Cat(); break; default: break; } return animal; } }
-
测试类FactoryTest.class
public class FactoryTest { public static void main(String[] args) { AnimalFactory factory=new AnimalFactory(); Animal dog = factory.createAnimal("dog"); dog.say(); Animal cat = factory.createAnimal("cat"); cat.say(); } }
完整样例
package com.company.factory;
/**
* 接口,标准规范类
*/
interface Animal {
void say();
}
/**
* 子类1
*/
class Dog implements Animal {
@Override
public void say() {
System.out.println("汪!");
}
}
/**
* 子类2
*/
class Cat implements Animal {
@Override
public void say() {
System.out.println("喵!");
}
}
/**
* 工厂
*/
class AnimalFactory {
public Animal createAnimal(String name) {
Animal animal = null;
switch (name) {
case "dog":
animal = new Dog();
break;
case "cat":
animal = new Cat();
break;
default:
break;
}
return animal;
}
}
/**
* 测试类
*/
public class FactoryTest {
public static void main(String[] args) {
AnimalFactory factory = new AnimalFactory();
Animal dog = factory.createAnimal("dog");
dog.say();
Animal cat = factory.createAnimal("cat");
cat.say();
}
}
结果
2.3.优点
工厂角色负责产生具体的实例对象,所以在工厂类中需要有必要的逻辑,通过客户的输入能够得到具体创建的实例;所以客户端就不需要感知具体对象是如何产生的,只需要将必要的信息提供给工厂即可
2.4.缺点
简单工厂模式是违反“开闭原则”,即对扩展开放,对修改关闭;因为如果要新增具体产品,就需要修改工厂类的代码,而不是在外部进行扩展
因此,衍生出了工厂方法模式,用于弥补解决这个缺点
3.工厂模式
3.1.介绍
工厂方法模式是对简单工厂模式进一步的解耦
定义一个用来创建对象的接口,让子类决定实例化哪一个类,让子类决定实例化延迟到子类。
工厂方法模式是针对每个产品提供一个工厂类,使用时判断用哪个工厂类去创建对象
包括四个角色
- 抽象产品接口:声明所有产品的公共方法
- 具体产品类:按照自己的需求实现抽象接口的方法
- 抽象工厂接口:声明所有公共内场的公共创建方法
- 具体工厂类:按照产品的需求实现抽象工厂的方法
3.2.实现
-
定义抽象产品接口
interface Animal { void say(); }
-
定义两个产品子类,实现抽象产品方法
class Dog implements Animal { @Override public void say() { System.out.println("汪!"); } } class Cat implements Animal { @Override public void say() { System.out.println("喵!"); } }
-
定义抽象工厂接口
interface AnimalFactory { Animal createAnimal(); }
-
定义两个工厂子类,实现抽象工厂方法
class DogFactory implements AnimalFactory { @Override public Animal createAnimal() { return new Dog(); } } class CatFactory implements AnimalFactory { @Override public Animal createAnimal() { return new Cat(); } }
-
测试类
public class FactoryTest2 { public static void main(String[] args) { AnimalFactory dogFactory = new DogFactory(); Animal dog = dogFactory.createAnimal(); dog.say(); AnimalFactory catFactory = new CatFactory(); Animal cat = catFactory.createAnimal(); cat.say(); } }
完整代码
package com.company.factory;
/**
* 接口,标准规范类
*/
interface Animal {
void say();
}
/**
* 子类1
*/
class Dog implements Animal {
@Override
public void say() {
System.out.println("汪!");
}
}
/**
* 子类2
*/
class Cat implements Animal {
@Override
public void say() {
System.out.println("喵!");
}
}
/**
* 公共工厂接口
*/
interface AnimalFactory {
Animal createAnimal();
}
/**
* 工厂1
*/
class DogFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
/**
* 工厂2
*/
class CatFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
}
/**
* 测试类
*/
public class FactoryTest2 {
public static void main(String[] args) {
AnimalFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.say();
AnimalFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.say();
}
}
运行结果
3.3.优点
- 工厂方法用来创建客户所需要的产品,同时隐藏了哪种具体产品类将被实例化的细节,用户只需要要关注工厂,不需要关注创建的细节
- 在增加和修改子类的时候不用修改其他产品和工厂的代码,只需要增加和修改自身产品和工厂就好,完全符合开放—封闭性原则
- 创建对象的细节完全封装在具体的工厂内部,而且有了抽象的工厂类,所有的具体工厂都继承了自己的父类,完美的体现了多态性
3.4.缺点
- 在增加新的产品时,也必须增加新的工厂类,会带来额外的开销
- 抽象层的加入使得理解程度加大
4.抽象工厂模式
4.1.介绍
抽象工厂模式是工厂方法模式的进一步延伸,提供功能更为强大的工厂类并且具备较好的可扩展性
说白了就是在抽象工厂接口中定义方法,使得每次添加一类产品,只需要在工厂接口中新增一个创建产品的接口,并在具体子工厂中实现新产品的创建即可
4.2.实现
跟工厂方法基本一致,直接贴全部代码了
package com.company.factory;
/**
* 接口,标准规范类
*/
interface Animal {
void say();
}
/**
* 子类1
*/
class Dog implements Animal {
@Override
public void say() {
System.out.println("汪!");
}
}
/**
* 子类2
*/
class Cat implements Animal {
@Override
public void say() {
System.out.println("喵!");
}
}
/**
* 接口,标准规范类
*/
interface Food {
void feed();
}
/**
* 子类1
*/
class DogFood implements Food {
@Override
public void feed() {
System.out.println("meat!");
}
}
/**
* 子类2
*/
class CatFood implements Food {
@Override
public void feed() {
System.out.println("fish!");
}
}
/**
* 公共工厂接口
*/
interface AnimalFactory {
Animal createAnimal();
Food createFood();
}
/**
* 工厂1
*/
class DogFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
@Override
public Food createFood() {
return new DogFood();
}
}
/**
* 工厂2
*/
class CatFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
@Override
public Food createFood() {
return new CatFood();
}
}
/**
* 测试类
*/
public class FactoryTest2 {
public static void main(String[] args) {
AnimalFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.say();
Food dogFood=dogFactory.createFood();
dogFood.feed();
AnimalFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.say();
Food catFood=catFactory.createFood();
catFood.feed();
}
}
结果
4.3.优点
- 易于添加产品类别,除了产品类本身以外,只需要在工厂接口中添加对应的方法,并加以实现即可
- 创建实例的过程与客户端分离,客户端只需要知道是哪种产品就行了,而无需知道如何创建的
4.4.缺点
- 添加产品子类较麻烦,如我想添加一个子类
panda
,那么我需要增加对应的子类,还需要增加对应的工厂类 - 使用时需要生成产品对应的工厂类,如果有N种产品则需要N个工厂类
其实还了解到一些在此基础上的变型,比如所有产品使用同一个接口,根据接收到的数据直接映射出产品,添加产品也就不用修改工厂了,但这样已经违背了工厂模式的初衷,即统一管理,有兴趣可以试试,但此处不多做阐述
5.后记
大部分引入的依赖或者工具类等,都会使用工厂模式,来隐藏细节,而仅提供给我们创建和使用方法
这样我们无需知道具体如何实现(虽然自己去看源码是个好习惯),仅仅知晓所提供给我们的公共方法即可掌握其使用方法,方便快捷
自己码代码的时候,不一定非得遵从工厂模式,但这种隐藏细节,而仅提供使用方法接口的做法,是值得我们学习的好习惯
作者:Echo_Ye
WX:Echo_YeZ
EMAIL :[email protected]
个人站点:在搭了在搭了。。。(右键 - 新建文件夹)