传统new对象:
在软件开发中,创建对象通常看起来只是简单地使用 new
关键字来实现。然而,直接使用 new
创建对象可能会导致一些问题,例如:
-
耦合性增加:如果在代码的多个地方直接使用
new
来创建对象,那么代码就会与具体的类耦合在一起。如果以后需要更改对象的创建方式或者替换具体的类,那么所有使用new
的地方都需要修改,这会增加代码的维护成本。 -
可测试性差:直接使用
new
创建对象的代码很难进行单元测试,因为它们与对象的创建逻辑紧密耦合在一起。如果对象的创建方式发生变化,那么测试代码也需要相应地修改。 -
违反了开闭原则:直接使用
new
创建对象会导致代码对具体类的依赖性增加,违反了开闭原则(Open Closed Principle)。开闭原则要求软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。直接使用new
创建对象会导致在需要新增功能或者修改现有功能时,必须修改已有代码。
工厂模式的运用:
工厂模式的引入正是为了解决传统直接使用 new
创建对象所带来的问题。通过引入工厂模式,可以降低代码的耦合性,提高代码的可维护性和可测试性,同时符合开闭原则。
首先,让我们看看工厂模式是如何解决传统创建对象的问题的:
-
降低耦合性:工厂模式将对象的创建逻辑封装在一个单独的类中,客户端代码只需要与工厂接口进行交互,而不需要直接与具体类进行交互。这样,如果以后需要更改对象的创建方式或者替换具体的类,只需要修改工厂类,而不需要修改客户端代码。
-
提高可维护性和可测试性:由于客户端代码不再直接与具体类耦合,所以代码的可维护性和可测试性得到了提高。例如,如果需要对对象的创建方式进行修改,只需要修改工厂类,而不需要修改客户端代码。这也使得单元测试更加容易进行,因为可以通过模拟工厂类来轻松地进行测试。
-
符合开闭原则:工厂模式符合开闭原则,因为它将对象的创建逻辑封装在一个单独的类中,使得客户端代码对扩展开放、对修改关闭。如果需要新增功能或者修改现有功能,只需要修改工厂类,而不需要修改客户端代码,从而保持了代码的稳定性和可维护性。
三种工厂设计模式:
-
简单工厂模式
简单工厂模式是最简单的工厂模式之一,它通过一个单独的工厂类来创建对象,而不需要暴露对象创建的具体细节。
在简单工厂模式中,客户端代码只需要向工厂类传递一个参数,工厂类根据参数的不同来创建不同的对象。
简单工厂模式适用于创建的对象较少且不会频繁变化的情况。
让我们通过代码来看简单工厂的例子
我们抽象出一个产品类,它可能是联想,戴尔,华硕等实例对象
package com.haiyang.campusrunner.product;
public abstract class Computer {
public void doSomething() {}
}
现在我们实例化这个抽象出来的产品类,我们实例化出联想,戴尔
package com.haiyang.campusrunner.product;
public class Lenovo extends Computer {
@Override
public void doSomething() {
System.out.println("Lenovo doSomething");
}
}
package com.haiyang.campusrunner.product;
public class Dell extends Computer {
@Override
public void doSomething() {
System.out.println("Dell doSomething");
}
}
现在我们的产品已经有具体的信息了,下面我们建立具体的工厂去生产这个产品类
package com.haiyang.campusrunner.factory;
import com.haiyang.campusrunner.product.Computer;
import com.haiyang.campusrunner.product.Dell;
import com.haiyang.campusrunner.product.Lenovo;
public class SimpleFactory {
public static Computer getProductA(String type)
{
if ("Lenovo".equals(type))
{
return new Lenovo();
}
else if ("Dell".equals(type))
{
return new Dell();
}
else
{
return null;
}
}
}
通过这个工厂类,我们就可以根据需要动态的生产对应的产品类了,这就是工厂
下面我们测试一下
package com.haiyang.campusrunner.test;
import com.haiyang.campusrunner.factory.SimpleFactory;
import com.haiyang.campusrunner.product.Computer;
import org.junit.jupiter.api.Test;
import org.springframework.stereotype.Component;
@Component
public class SimpleFactoryTest {
@Test
public void test(){
Computer product = SimpleFactory.getProductA("Lenovo");
assert product != null;
product.doSomething();
Computer product1 = SimpleFactory.getProductA("Dell");
assert product1 != null;
product1.doSomething();
}
}
通过输出
简单工厂的设计模式就是通过具体的工厂类设计,但是缺点在于随着产品类的增多,还需要进一步修改工厂类代码,并且还会增加代码的复杂度,通过这一个问题,我们就引入了工厂方法模式
-
工厂方法模式
工厂方法模式,就是进一步将工厂抽象出来,通过继承或者实现的方式,来进一步降低工厂的复杂度,来解决上述的问题
产品代码不变,工厂这样写:
package com.haiyang.campusrunner.factory;
import com.haiyang.campusrunner.product.Computer;
public interface FactoryMethodFactory {
Computer createProduct();
}
通过抽象工厂,我们继承或者实现,我们将工厂类中的代码彻底解放出来,避免了简单工厂随着产品增加代码规模进一步增加带来的代码规模增加以及阅读的复杂度
package com.haiyang.campusrunner.factory;
import com.haiyang.campusrunner.product.Computer;
import com.haiyang.campusrunner.product.Lenovo;
public class FactoryMethodFactoryA implements FactoryMethodFactory{
@Override
public Computer createProduct() {
return new Lenovo();
}
}
另一个工厂
package com.haiyang.campusrunner.factory;
import com.haiyang.campusrunner.product.Computer;
import com.haiyang.campusrunner.product.Dell;
public class FactoryMethodFactoryB implements FactoryMethodFactory {
@Override
public Computer createProduct() {
return new Dell();
}
}
编写测试方法
package com.haiyang.campusrunner.test;
import com.haiyang.campusrunner.factory.FactoryMethodFactory;
import com.haiyang.campusrunner.factory.FactoryMethodFactoryA;
import com.haiyang.campusrunner.factory.FactoryMethodFactoryB;
import org.junit.jupiter.api.Test;
public class FactoryMethodTest {
@Test
public void test()
{
FactoryMethodFactory factoryA = new FactoryMethodFactoryA();
factoryA.createProduct().doSomething();
FactoryMethodFactory factoryB = new FactoryMethodFactoryB();
factoryB.createProduct().doSomething();
}
}
运行结果
-
抽象工厂模式
抽象工厂模式是一种创建型设计模式,旨在提供一个接口,用于创建一系列相关或依赖的对象家族,而无需指定具体的类。在抽象工厂模式中,有一个抽象工厂接口,该接口定义了用于创建这些相关对象的方法。然后,有一组具体的工厂类实现了这个接口,每个工厂类都负责创建一组相关的对象。客户端代码通过与抽象工厂接口进行交互,而不需要关心具体的工厂类或对象的创建细节。
抽象工厂模式的核心思想是将对象的创建与客户端代码解耦,使得客户端代码可以独立于具体的对象类进行编写。这种解耦提高了代码的灵活性和可维护性,因为客户端代码不需要了解对象的创建细节,而只需要与抽象工厂接口进行交互。如果需要更改或扩展对象的创建方式,只需修改相应的工厂类即可,而不需要修改客户端代码。
抽象工厂模式通常适用于以下场景:
- 当系统中有多个相关的对象家族,并且这些对象家族需要一起使用时,可以使用抽象工厂模式来管理这些对象之间的依赖关系。
- 当希望将对象的创建逻辑与客户端代码解耦时,可以使用抽象工厂模式来隐藏对象的创建细节。
- 当需要在运行时动态切换不同的对象家族时,抽象工厂模式可以提供一种灵活的解决方案。
其实说那么多,不如大家一看代码就明白了
产品类再增加一类新产品,假如说是汽车类吧
那么实例化汽车类就是宝马,福特,那现在我们有两个产品类了
package com.haiyang.campusrunner.product;
public class BMW extends Car {
@Override
public void car() {
System.out.println("BMW");
}
}
package com.haiyang.campusrunner.product;
public class Ford extends Car {
@Override
public void car() {
System.out.println("Ford");
}
}
抽象工厂类
package com.haiyang.campusrunner.factory;
import com.haiyang.campusrunner.product.Car;
import com.haiyang.campusrunner.product.Computer;
public interface AbstractFactory {
Computer createComputer();
Car createCar();
}
具体的实例工厂类
package com.haiyang.campusrunner.factory;
import com.haiyang.campusrunner.product.BMW;
import com.haiyang.campusrunner.product.Car;
import com.haiyang.campusrunner.product.Computer;
import com.haiyang.campusrunner.product.Lenovo;
public class AbstractFactoryA implements AbstractFactory {
@Override
public Computer createComputer() {
return new Lenovo();
}
@Override
public Car createCar() {
return new BMW();
}
}
package com.haiyang.campusrunner.factory;
import com.haiyang.campusrunner.product.Car;
import com.haiyang.campusrunner.product.Computer;
import com.haiyang.campusrunner.product.Dell;
import com.haiyang.campusrunner.product.Ford;
public class AbstractFactoryB implements AbstractFactory {
@Override
public Computer createComputer() {
return new Dell();
}
@Override
public Car createCar() {
return new Ford();
}
}
生成测试方法
package com.haiyang.campusrunner.test;
import com.haiyang.campusrunner.factory.AbstractFactory;
import com.haiyang.campusrunner.factory.AbstractFactoryA;
import com.haiyang.campusrunner.factory.AbstractFactoryB;
import org.junit.jupiter.api.Test;
public class AbstractFactoryTest {
@Test
public void test() {
AbstractFactory factoryA = new AbstractFactoryA();
factoryA.createComputer().doSomething();
factoryA.createCar().car();
AbstractFactory factoryB = new AbstractFactoryB();
factoryB.createComputer().doSomething();
factoryB.createCar().car();
}
}
总结:
-
简单工厂模式(Simple Factory Pattern):
- 特点:
- 简单工厂模式由一个单独的工厂类负责创建对象。
- 客户端代码通过传递不同的参数给工厂类来获取不同类型的对象。
- 工厂类根据参数的不同来实例化不同的对象。
- 联系:
- 简单工厂模式是工厂模式的最基本形式,也是最简单的一种。
- 它适用于对象创建逻辑比较简单的场景,且创建的对象较少,不会频繁变化。
- 特点:
-
工厂方法模式(Factory Method Pattern):
- 特点:
- 工厂方法模式定义了一个创建对象的接口,但是将对象的实际创建推迟到子类中。
- 客户端代码通过调用工厂类的方法来创建对象,而具体的对象创建逻辑由子类实现。
- 每个子类对应创建一个具体的对象,从而使得对象的创建可以通过子类来定制化。
- 联系:
- 工厂方法模式也是用来创建对象的,但是它将对象的创建过程交给了子类来实现,从而实现了更大程度的灵活性和可扩展性。
- 它与简单工厂模式相比,更加符合开闭原则,因为新增功能或者修改现有功能时,只需要添加或修改相应的子类,而不需要修改已有代码。
- 特点:
-
抽象工厂模式(Abstract Factory Pattern):
- 特点:
- 抽象工厂模式提供一个接口,用于创建一系列相关或依赖的对象家族,而不需要指定具体的类。
- 客户端代码通过与抽象工厂接口进行交互来获取一组相关的对象,而具体的工厂类负责创建这些对象的实例。
- 抽象工厂模式可以帮助管理对象之间的依赖关系,并使得代码更加灵活、可维护和可扩展。
- 联系:
- 抽象工厂模式与简单工厂模式和工厂方法模式不同,它不仅可以创建单个对象,还可以创建一组相关的对象。
- 它提供了更高层次的抽象,能够管理复杂的对象家族之间的依赖关系。
- 特点:
这三种工厂设计模式在实际应用中根据不同的需求和场景选择使用,它们都旨在提供一种灵活、可维护和可扩展的对象创建方案,同时也遵循了面向对象设计原则中的开闭原则和单一职责原则。