工厂办法形式
前语
今天想聊一下陈词滥调的一种形式,工厂办法形式。别的本文中会呈现很多的代码,不过都很简略容易理解。
下面两张图,是本文中可能会用到的。感兴趣的能够看一下。期望我们能够看完本文,喜欢的话能够点个赞支持下。
常见的规划准则
工厂形式的种类
讲个故事
这几年新能源车比较盛行。特斯拉,比亚迪,五菱等车企都在发展新能源车。轿车嘛,品牌不同,配置不同,价格也不太相同。毕业生小白就职于一家轿车媒体公司,一天组长把他叫来,让他搜集一下这些车企新能源车的相关信息。今天的故事就从这儿开始了。
正常的写法
收到使命后的小白心想,这个使命太简略了,没有任何难度。所以他立刻开始着手,因此有了下面这份代码。
产品类
// 比亚迪类
class BYD{
public void name() {
System.out.println("比亚迪");
}
public void price() {
System.out.println("22万");
}
public void kind() {
System.out.println("新能源");
}
}
// 特斯拉类
class TSLA{
public void name() {
System.out.println("特斯拉");
}
public void price() {
System.out.println("32万");
}
public void kind() {
System.out.println("新能源轿车");
}
}
客户端类
// 客户端调用代码
class Client {
public static void main(String[] args) {
BYD byd = new BYD();
TSLA tsla = new TSLA();
}
}
现在看着还算不错,两个品牌都有了自己的目标。所以他立刻把代码交给组长看。
普通写法遇到的问题
组长看过之后,对他说:
现在来说,只要两个品牌还好,可是后面的事务必定还要发展,品牌必定不止一个。
假如Client中有10个轿车品牌,100个轿车品牌该怎么办?难道一个Client类要和100个轿车品牌的类都有相关吗?迪米特法则——最少知道准则,难道你没听过吗?
一旦100个类中的一个类进行修正,就可能导致Client类呈现问题!
你去比照下规划准则,看下问题出在哪儿!!!
简略工厂形式的写法
小白,细心看了一遍代码,发现现在这种写法确实是耦合过于严重。Client类会和每个用到的轿车产品类发生相关。
不过好在能够用依赖反转 + 封装的办法修正原有代码,处理这个问题。
- 将轿车都有的属性或许办法办法抽离到轿车接口中
- 一切的轿车产品都完成轿车接口。这样能够经过多态的特性,将Client类与轿车产品之间进行解耦。
- 将一切目标的创立过程封装到一个管理类中,这个类能够叫做Manager或许Factory。
简略工厂形式的代码
1.将公共的办法抽离到接口中
/**
* @author jtl
* @date 2021/7/20 16:18
*/
interface Car {
void name();
void price();
void kind();
}
2.轿车品牌完成该接口
class BYD implements Car {
@Override
public void name() {
System.out.println("比亚迪");
}
@Override
public void price() {
System.out.println("22万");
}
@Override
public void kind() {
System.out.println("新能源");
}
}
class BMW implements Car{
@Override
public void name() {
System.out.println("宝马");
}
@Override
public void price() {
System.out.println("40万");
}
@Override
public void kind() {
System.out.println("燃油车");
}
}
class Tesla implements Car {
@Override
public void name() {
System.out.println("特斯拉");
}
@Override
public void price() {
System.out.println("32万");
}
@Override
public void kind() {
System.out.println("新能源轿车");
}
}
3.轿车的管理工厂类
class CarFactory {
public static Car getCar(String name) {
Car car =null ;
switch (name){
case "宝马":
car = new BMW();
break;
case "特斯拉":
car = new TSLA();
break;
case "比亚迪":
car = new BYD();
break;
default:
break;
}
return car;
}
}
4.客户端调用
class Client {
public static void main(String[] args) {
Car car = CarFactory.getCar("比亚迪");
Car car = CarFactory.getCar("特斯拉");
Car car = CarFactory.getCar("宝马");
}
}
简略工厂遇到的问题
经过简略工厂形式,让Client类只和Car还有CarFactory打交道,降低了耦合度,哪怕呈现1000个轿车品牌,也都和Client类没有关系了。
可是随之而来的是一个新的问题。每非必须新增轿车品牌,都要修正Factory类中的办法。这可是违反了规划准则中的最关键的一条准则之一,开闭准则,即对扩展开放对修正封闭。
而且虽然Client类耦合度下来了,可是一切的轿车类都和Factory类有了相关。这仍旧违反迪米特法则——最少知道准则。
工厂办法形式
正在小白束手无策的时分,组长走了过来对他说。你能想到这一步现已很出色了,我这儿有一份代码现已上传到GitLab上,里面用到了工厂办法形式。你拉取一下看看写法。随后不等小白说谢就回身离开了。小白把代码拉下来之后就看到了下面的代码。
正常办法完成的工厂办法
笼统产品代码
/**
* Author(作者):jtl
* Date(日期):2023/2/8 14:17
* Detail(概况):笼统产品接口
*/
public interface ICar {
void name();
void price();
}
实际产品代码
/**
* Author(作者):jtl
* Date(日期):2023/2/8 14:20
* Detail(概况):详细产品类----比亚迪电动车
*/
public class BYD implements ICar{
@Override
public void name() {
System.out.println("比亚迪新能源电动车");
}
@Override
public void price() {
System.out.println("20W");
}
}
/**
* Author(作者):jtl
* Date(日期):2023/2/8 14:21
* Detail(概况):详细产品类---特斯拉电动车
*/
public class TSLA implements ICar{
@Override
public void name() {
System.out.println("特斯拉新能源电动车");
}
@Override
public void price() {
System.out.println("28W");
}
}
笼统工厂代码
/**
* Author(作者):jtl
* Date(日期):2023/2/8 14:18
* Detail(概况):笼统工厂接口
*/
public interface IFactory {
ICar buildCar();
}
实际工厂代码
/**
* Author(作者):jtl
* Date(日期):2023/2/8 14:23
* Detail(概况):详细工厂类---比亚迪新能源工厂
*/
public class BYDFactory implements IFactory{
@Override
public ICar buildCar() {
return new BYD();
}
}
/**
* Author(作者):jtl
* Date(日期):2023/2/8 14:24
* Detail(概况):详细工厂类---特斯拉上海工厂
*/
public class TSLAFactory implements IFactory{
@Override
public ICar buildCar() {
return new TSLA();
}
}
客户端调用代码
/**
* Author(作者):jtl
* Date(日期):2023/2/8 14:24
* Detail(概况):工厂办法形式客户端
*/
public class Client {
public static void main(String[] args) {
IFactory bydFactory = new BYDFactory();
bydFactory.buildCar().name();
IFactory tslaFactory = new TSLAFactory();
tslaFactory.buildCar().name();
}
}
为了处理,简略工厂形式违反开闭准则和迪米特法则——最少知道准则。组长对简略工厂进行了修正。
- 将轿车共有的属性或许办法抽离到**轿车接口(ICar)**中
- 一切的轿车产品(TSLA,BYD等) 都完成轿车接口(ICar)。这样能够经过多态的特性,进行Client类与轿车产品之间的解耦。
- 将创立轿车产品TSLA,BYD等) 的功能进行抽离封装到IFactory工厂接口中
- 每一个轿车产品(TSLA,BYD等) 都有自己的完成了IFactory接口的轿车工厂(TSLAFactory,BYDFactory等)
新的问题
虽然说,工厂办法形式处理了简略工厂中Factory类和各种轿车产品类耦合度过高的问题。而且再也不必,每次新增一个轿车产品就去简略工厂中修正代码了。
可是工厂办法形式有一个致命的问题就是,每新增一个轿车品牌就要增加一个轿车产品和轿车工厂。今天新增个五菱的轿车和五菱工厂,明日再新增个抱负的轿车和抱负的工厂。新增1000个轿车品牌就要新增1000个轿车和工厂。这样下去class的数量就会过多。这是一个不可忽视的问题。
经过反射完成的工厂办法
小白把他想到的问题,如数家珍的告知了组长。组长非常安慰的看着小白说,你能想到这个问题很好,说明你进步了。工厂办法形式确实会呈现这样的问题。因此我用反射写了一份工厂办法形式的代码,虽然说和轿车没关系,可是你能够类比一下。究竟不能什么都和轿车有关系啊!
笼统工厂代码
对应IFactory
public abstract class Factory {
public abstract <T extends Product> T createProduct(Class<T> clazz);
}
笼统产品代码
对应ICar
public abstract class Product {
abstract void method();
}
详细工厂代码
对应BYDFactory等轿车工厂
public class ConcreteFactory extends Factory{
// 经过反射的办法创立详细工厂,处理了,一个详细工厂对应一个详细产品的问题
@Override
public <T extends Product> T createProduct(Class<T> clazz) {
Product product = null;
try {
product = (Product) Class.forName(clazz.getName()).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return (T) product;
}
}
详细产品代码
对应BYD,TSLA等轿车产品
public class ConcreteProductA extends Product{
@Override
void method() {
System.out.println("详细产品A");
}
}
public class ConcreteProductB extends Product{
@Override
void method() {
System.out.println("详细产品B");
}
}
客户端代码完成
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory();
Product productA = factory.createProduct(ConcreteProductA.class);
Product productB = factory.createProduct(ConcreteProductB.class);
productA.method();//详细产品A
productB.method();//详细产品B
}
}
反射工厂办法中的妥协
经过反射的办法,处理了工厂办法形式中,过多的产品导致的产品工厂过多的问题。可是,Client类又和产品类有了一些耦合。只能说,没有十全十美的规划形式,只要合不适宜。
枯燥无味的定义
听完了故事,就来看一下,官方说法的定义和运用场景吧,
相关定义
工厂办法形式分为四个组成部分,笼统工厂,笼统产品,详细工厂,详细产品。
工厂办法形式属于创立型规划形式。是为了将目标的创立与Client类解耦。
工厂会回来目标给Client,Client不知道创立的详细细节。
运用场景
1. 有很多相同属性的同类型目标。
2. 需要将这些目标的创立对客户端进行解耦。
运用步骤
1. 将具有相同特征的目标的共同特征进行提取。生成笼统产品类。
2. 生成承继笼统产品的详细产品。
3. 创立笼统工厂,生成回来笼统产品的笼统办法。
4. 生成创立详细产品的详细工厂,该工厂承继笼统工厂。重写笼统办法,回来详细产品的目标。
注意事项
- 优点,将目标的创立与客户端代码别离完成解耦。
- 缺陷,每新增一个种类就要新增一个笼统产品和笼统工厂。
- 提升,能够用反射的办法完成详细工厂,而不是每有一个详细产品就创立一个与之相对应的详细工厂。能够减少代码量。
总结
至此,工厂办法形式就讲完了。简略工厂能够看作是工厂办法形式的一种。假如是简略的创立同类型目标的话,简略工厂形式就能够担任了。可是假如是大的项目,还是引荐运用工厂办法形式进行解耦。至所以运用正常的工厂办法,还是反射的工厂办法,那就完全看个人的选择了。究竟,只要适宜才是最好的!
别的,工厂办法形式的运用前提是,很多的同类型的目标的创立,这点可千万别记错了。