设计模式在开发中的应用 -- 工厂模式
简单工厂
这个模式本身很简单而且使用在业务较简单的情况下。一般用于小项目或者具体产品很少扩展的情况(这样工厂类才不用经常更改)。 它由三种角色组成:
工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,根据逻辑不同,产生具体的工厂产品。如例子中的Driver类。
抽象产品角色:它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。如例中的Car接口。
具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现,如例子中的Benz、Bmw类。
工厂方法
工厂方法模式:有四个角色,抽象工厂模式,具体工厂模式,抽象产品模式,具体产品模式。不再是由一个工厂类去实例化具体的产品,而是由抽象工厂的子类去实例化产品
定义一个接口
public interface Moveable {
void run();
}
两个实现类
public class Car implements Moveable {
@Override
public void run() {
System.out.println("car...");
}
}
public class Plane implements Moveable {
@Override
public void run() {
System.out.println("Plane...");
}
}
定义一个抽象工厂
public abstract class VehicleFactory {
abstract Moveable create();
}
两个具体工厂
public class PlaneFactory extends VehicleFactory {
@Override
Moveable create() {
return new Plane();
}
}
public class CarFactory extends VehicleFactory
{
@Override
Moveable create() {
return new Car();
}
}
测试类
public class Test {
public static void main(String[] args) {
VehicleFactory factory = new CarFactory();
Moveable moveable = factory.create();
moveable.run();
}
}
运行结果
抽象工厂
提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
与工厂方法模式不同的是,工厂方法模式中的工厂只生产单一的产品,而抽象工厂模式中的工厂生产多个产品
一个login和user实体类
@Data
@ToString
public class User {
private int id;
private String username;
private String password;
}
@Data
@ToString
public class Login {
private int id;
private Date date;
}
定义三个接口
public interface IFactory {
IUser createUser();
ILogin createLogin();
}
public interface ILogin {
void insert(Login login);
Login getLogin(int id);
}
public interface IUser {
void insert(User user);
IUser getUser(int uid);
}
两个具体工厂
public class MysqlFactory implements IFactory {
@Override
public IUser createUser() {
return new MysqlUser();
}
@Override
public ILogin createLogin() {
return new MysqlLogin();
}
}
public class OracleFactory implements IFactory {
@Override
public IUser createUser() {
return new OracleUser();
}
@Override
public ILogin createLogin() {
return new OracleLogin();
}
}
具体的产品
public class MysqlLogin implements ILogin {
@Override
public void insert(Login login) {
System.out.println("对 MySQL 里的 Login 表插入了一条数据");
}
@Override
public Login getLogin(int id) {
System.out.println("通过 uid 在 MySQL 里的 Login 表得到了一条数据");
return null;
}
}
public class MysqlUser implements IUser {
@Override
public void insert(User user) {
System.out.println("对 MySQL 里的 user 表插入了一条数据");
}
@Override
public IUser getUser(int uid) {
System.out.println("通过 uid 在 MySQL 里的 user 表得到了一条数据");
return null;
}
}
public class OracleLogin implements ILogin {
@Override
public void insert(Login login) {
System.out.println("对 Oracle 里的 Login 表插入了一条数据");
}
@Override
public Login getLogin(int id) {
System.out.println("通过 uid 在 Oracle 里的 Login 表得到了一条数据");
return null; }
}
public class OracleUser implements IUser {
@Override
public void insert(User user) {
System.out.println("对 Oracle 里的 user 表插入了一条数据");
}
@Override
public IUser getUser(int uid) {
System.out.println("通过 uid 在 Oracle 里的 Login 表得到了一条数据");
return null;
}
}
客户端
public class Client {
public static void main(String[] args) {
User user = new User();
Login login = new Login();
// 只需要确定实例化哪一个数据库访问对象给factory
IFactory factory = new MysqlFactory();
// 已与具体的数据库访问解除了耦合
IUser user1 = factory.createUser();
user1.getUser(1);
user1.insert(user);
ILogin login1 = factory.createLogin();
login1.getLogin(1);
login1.insert(login);
}
}
运行结果
从客户端的代码中,我们只需要更改 IFactory factory=new MysqlFactory(); 为 IFactory factory=new OracleFactory();,就实现了数据库访问的切换。而且实际上我们这次代码的重构已经使用到了抽象工厂模式,抽象工厂可能表面上看起来貌似与工厂方法模式没什么区别,其实不然,所以我之前才说抽象工厂模式是基于工厂方法模式的。
只有一个User表的封装类和User表的操作类时,我们只用到了工厂方法模式,而且也只需要使用到工厂方法模式。但是显然现在我们的数据库已经不止一个User表了,而 MySQL 和 Oracle 又是两大不同的分类,所以解决这种涉及到多个产品系列的问题,就需要使用到专门解决这种问题的模式:抽象工厂模式。这时候再回过头去看DP对抽象工厂模式的定义就不难理解了。
所以抽象工厂与工厂方法模式的区别在于:抽象工厂是可以生产多个产品的,例如 MysqlFactory 里可以生产 MysqlUser 以及 MysqlLogin 两个产品,而这两个产品又是属于一个系列的,因为它们都是属于MySQL数据库的表。而工厂方法模式则只能生产一个产品,例如之前的 MysqlFactory 里就只可以生产一个 MysqlUser 产品。