1.概念
工厂模式是一种创建型模式(什么是创建型模式,见我发布的单例模式详解文章,或者狗子们自己百度下),它提供了一种创建对象的最佳方式。在此模式下,我们使用工厂类创建对象,而非使用new关键字实例化对象。
工厂模式的主要目的是将对象的创建与使用分离,使代码更加灵活和可维护。它通过将对象的创建委托给工厂类来实现,工厂类根据不同的条件或参数来决定创建哪种类型的对象。
2.要素
工厂模式通常包含以下几个角色:
- 抽象产品(Product):定义了产品的接口,所有具体产品都必须实现这个接口。
- 具体产品(Concrete Product):实现了抽象产品接口的具体类。
- 抽象工厂(Abstract Factory):定义了创建产品的接口,包含一个或多个创建产品的方法。
- 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体产品的对象。
3.举例
下面是一个工厂模式常见的经典例子:
其实每次定义代码结构之前,要先抽象需求,这个慢慢要培养。
首先我们定义一个产品的抽象接口。
复习下
Java接口也是抽象的,为什么?因为接口没有具体的实现,其实没有具体实现的都可以看做是抽象的。抽象对应具体,是不是又学到了。
车是抽象的(不要抬杠,我们认为只有具体车型的车是具体的),定义个抽象的车的接口,接口定义一个驾驶方法,
比如分自动挡和手动挡的驾驶,但是不管怎样,车肯定都要能驾驶(家庭开支之后,我特喵现在连个车都买不起,狗子们多努力)
// 抽象产品
interface Car
{
void drive();
}
定义手动挡实现类
class SdCar implements Car {
@Override
public void drive() {
System.out.println("手动挡驾驶");
}
}
定义自动挡实现类
class ZdCar implements Car {
@Override
public void drive() {
System.out.println("自动挡驾驶");
}
}
这个时候我们不要new直接创建实例化对象,采用工厂方法:
定义一个创建车对象的接口方法,现在懵逼不要急
// 抽象工厂
interface CarFactory {
Car CreateCar();
}
我们再分别创建自动挡和手动挡车的实现类,都是工厂概念
class ZdCarFactory implements CarFactory {
@Override
public Car CreateCar() {
return new ZdCar();
}
}
class SdCarFactory implements CarFactory {
@Override
public Car CreateCar() {
return new SdCar();
}
}
我们看怎么使用上面,也就是以客户端的代码:
// 客户端代码
public class Main {
public static void main(String[] args) {
//工厂级别
CarFactory sd_factory=new SdCarFactory();
//具体的车级别实例
Car sd_car=sd_factory.CreateCar();
sd_car.drive()
//工厂级别
CarFactory zd_factory=new ZdCarFactory();
//具体的车级别实例
Car zd_car=zd_factory.CreateCar();
zd_car.drive()
}
}
有些人到客户端就看不懂了,我来给狗子们复习下下面知识。
接口是不能被实例化的,也就是说接口不能使用new创建实例化对象,为什么?因为接口是抽象的,new是实例化之后具体的。
但是接口可以指向实现类的对象,也叫向上造型(upcasting)。向上造型是安全的,因为接口是实现类的抽象,可以保证实现类实现了接口中定义的所有方法。这种其实就叫“多态性”。
对应的向下造型(downcasting)是将一个父类对象转换为子类对象的过程。在Java中,如果一个接口指向实现类的对象,然后将该接口转换为实现类类型,这被称为向下造型。向下造型是不安全的,因为接口可能没有实现类的特定方法或属性,这样的转换可能会导致运行时异常。因此,在进行向下造型时,应该先使用instanceof运算符进行类型检查,以确保对象的类型是正确的。向下造型一般用在继承当中,继承就不用复习了吧。
所以举一个案例:
Java向上造型
public interface Car {
void drive();
}
public class SDCar implements Car{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("手动挡驾驶");
}
}
public class ZDCar implements Car{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("自动挡驾驶");
}
}
客户端
public class Fatcory {
public static void main(String[] args) {
//接口指向了实现类的对象,肯定也实现了自己的方法,所以指向谁,调用
//接口的方法,就是谁的
Car car_zd =new ZDCar();
car_zd.drive();
//输出:自动挡驾驶
Car car_sd =new SDCar();
car_sd.drive();
//输出:手动挡驾驶
}
}
Java向下造型:
class Animal {
public void sound() {
System.out.println("动物类声音");
}
}
class Dog extends Animal {
public void sound() {
System.out.println("狗叫声,这个是子类重写父类的方法。。。。");
}
public void fetch() {
System.out.println("狗狗抓东西,这个是子类自己的方法。。。");
}
}
public class Main {
public static void main(String[] args) {
//父类子化,同接口,属于向上造型
Animal animal = new Dog(); // 向上造型,继承也有向上造型
animal.sound(); // 调用的是Dog类的sound方法
//子类父亲化,但是东西全都是自己的,相当于名义上构造了一个对象实例,操作的都是自己的
Dog dog = (Dog) animal; // 向下造型
dog.sound(); // 调用的是Dog类的sound方法
dog.fetch(); // 调用的是Dog类的fetch方法
}
}
4.总结
首先千万不要把工厂方法理解为单个到批量,这么理解是不对的,其实你想想,程序员文学水平能有多高。
其实是两次分别的接口向上造型,其实完全一次接口向上造就可以将创建对象,但是不符合封装的概念了。
工厂-->生产--->不同品牌有自己的生产方式-->生产出来的车要符合车的抽象概念,车-->都要能驾驶-->
不同种类的车有不同的驾驶方式。
使用的时候也是从工厂级别开始:
工厂接口 具体的工厂实现类对象=new 具体的工厂实现类(一次向上造型)
具体的工厂实现类对象调用抽象方法创建各自的Car对象(一次向上造型)
各自的Car对象调用各自的驾驶方法
这个时候顺便理解下向上造型。
5.应用场景
应用场景包括:
- 对象的创建需要复杂的逻辑或条件判断:工厂模式可以将对象的创建逻辑封装在工厂类中,根据不同的条件返回不同的对象实例。
- 需要统一管理对象的创建:工厂模式可以将对象的创建集中在一个工厂类中,方便管理和维护。
- 需要隐藏对象的创建细节:工厂模式可以将对象的创建细节隐藏在工厂类中,对外只暴露一个简单的接口,降低了使用者的复杂度。
- 需要动态地切换对象的实现:工厂模式可以通过修改工厂类的实现,实现对不同对象实现的切换,而不需要修改使用者的代码。
- 需要扩展对象的创建:工厂模式可以通过添加新的工厂类或修改现有的工厂类,实现对新对象的创建,而不需要修改使用者的代码。
总之,工厂模式适用于需要灵活、可扩展、可维护的对象创建场景。