工厂模式
简单工厂
实例化对象的时候不再使用new Object()的方式,可以根据用户的选择条件来实例化相关的类,对于客户端来说,去除了具体类的依赖。只需要给出具体实例的描述给工厂,工厂就会自动返回具体的实例对象
public interface Operation {
Double getResult(Double a, Double b);
}
新增操作实例类
public class AddClass implements Operation {
@Override
public Double getResult(Double a, Double b) {
return a + b;
}
}
减法操作实例类
public class SubClass implements Operation {
@Override
public Double getResult(Double a, Double b) {
return a - b;
}
}
乘法操作实例类
public class MultiplicationClass implements Operation {
@Override
public Double getResult(Double a, Double b) {
return a * b;
}
}
除法操作实例类
public class DivisionClass implements Operation {
@Override
public Double getResult(Double a, Double b) {
if(b == 0){
return null;
}
return a / b;
}
}
简单工厂,生产具体实例
public class SimpleFactory {
public static Operation createOperate(String type){
Operation operation =null;
switch (type){
case "+" :
operation = new AddClass();
break;
case "-":
operation = new SubClass();
break;
case "/":
operation = new DivisionClass();
break;
case "*":
operation = new MultiplicationClass();
break;
}
return operation;
}
}
消费方
public class Client {
public static void main(String[] args) {
Operation add = SimpleFactory.createOperate("+");
Operation sub = SimpleFactory.createOperate("-");
Operation division = SimpleFactory.createOperate("/");
Operation multiplication = SimpleFactory.createOperate("*");
System.out.println(add.getResult(2d,3d));
System.out.println(sub.getResult(2d,3d));
System.out.println(division.getResult(2d,3d));
System.out.println(multiplication.getResult(2d,3d));
}
}
优点:比较好了解,简单易操作。达到了解耦的作用,使用方不用考虑实例对象的内部具体细节,使用方通过简单工厂获取自己需要的实例对象。
缺点:违反了设计模式的OCP原则,即对扩展开发,对修改关闭。即我们给类增加新的功能的时候,尽量不修改代码,或者少修改代码。比如:当我新增新的运算操作时,需要修改简单工厂。
工厂方法
和简单工厂相比,工厂方法进一步解耦,把简单工厂进一步抽象出来一个工厂接口,由具体工厂来实现实例对象的生产,不用关注具体的细节
新增工厂接口
public interface Factory {
Operation createOperation();
}
各种操作的具体工厂
public class AddFactory implements Factory {
@Override
public Operation createOperation() {
System.out.println("加法运算");
return new AddClass();
}
}
public class SubFactory implements Factory{
@Override
public Operation createOperation() {
System.out.println("减法运算");
return new SubClass();
}
}
public class MultiplicationFactory implements Factory {
@Override
public Operation createOperation() {
System.out.println("乘法运算");
return new MultiplicationClass();
}
}
public class DivisionFactory implements Factory {
@Override
public Operation createOperation() {
System.out.println("除法运算");
return new DivisionClass();
}
}
产品管理接口
public interface Operation {
Double getResult(Double a, Double b);
}
各种产品类
public class AddClass implements Operation {
@Override
public Double getResult(Double a, Double b) {
return a + b;
}
}
public class SubClass implements Operation {
@Override
public Double getResult(Double a, Double b) {
return a - b;
}
}
public class MultiplicationClass implements Operation {
@Override
public Double getResult(Double a, Double b) {
return a * b;
}
}
public class DivisionClass implements Operation {
@Override
public Double getResult(Double a, Double b) {
if(b == 0){
return null;
}
return a / b;
}
}
使用方
//方式一:直接通过创建具体工厂使用接口
public class Client {
public static void main(String[] args) {
Factory add = new AddFactory();
Factory sub = new SubFactory();
Factory division = new DivisionFactory();
Factory multi = new MultiplicationFactory();
System.out.println(add.createOperation().getResult(2d,3d));
System.out.println(sub.createOperation().getResult(2d,3d));
System.out.println(division.createOperation().getResult(2d,3d));
System.out.println(multi.createOperation().getResult(2d,3d));
}
}
//方式二:通过配置文件中的类全路径通过反射机制获取具体工厂
public class Client {
public static void main(String[] args)throws Exception {
/*Factory add = new AddFactory();
Factory sub = new SubFactory();
Factory division = new DivisionFactory();
Factory multi = new MultiplicationFactory();*/
Factory add = (Factory) Class.forName("com.h3c.com.designpattrn.factory.factorymethod.AddFactory").newInstance();
Factory sub = (Factory) Class.forName("com.h3c.com.designpattrn.factory.factorymethod.SubFactory").newInstance();
Factory division = (Factory) Class.forName("com.h3c.com.designpattrn.factory.factorymethod.MultiplicationFactory").newInstance();
Factory multi = (Factory) Class.forName("com.h3c.com.designpattrn.factory.factorymethod.DivisionFactory").newInstance();
System.out.println(add.createOperation().getResult(2d,3d));
System.out.println(sub.createOperation().getResult(2d,3d));
System.out.println(division.createOperation().getResult(2d,3d));
System.out.println(multi.createOperation().getResult(2d,3d));
}
}
总结:
工厂模式中,要增加产品类时也要相应地增加工厂类,客户端的代码也增加了不少。工厂方法把简单工厂的内部逻辑判断转移到了客户端代码来进行。
你想要加功能,本来是改工厂类的,而现在是修改客户端。而且各个不同功能的实例对象的创建代码,也没有耦合在同一个工厂类里,这也是工厂方法模式对简单工厂模式解耦的一个体现。工厂方法模式克服了简单工厂会违背开-闭原则的缺点,又保持了封装对象创建过程的优点。
但工厂方法模式的缺点是每增加一个产品类,就需要增加一个对应的工厂类,增加了额外的开发量。
抽象工厂
产品接口(抽象出产品有哪些共同的操作)
public interface ILogin {
void insert(Login login);
Login getLogin(int id);
}
public interface IUser {
void insert(User user);
User getUser(int uid);
}
产品类
public class User {
private int uid;
private String uname;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
}
public class Login {
private int id;
private Date date;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
产品分类(具体产品分类有哪些操作)
public class MysqlUser implements IUser {
@Override
public void insert(User user) {
System.out.println("在mysql中的user表中插入一条元素");
}
@Override
public User getUser(int uid) {
System.out.println("在mysql中的user表得到uid为"+uid+"的一条数据");
return null;
}
}
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 OracleUser implements IUser {
@Override
public void insert(User user) {
System.out.println("在oracle中的user表中插入一条元素");
}
@Override
public User getUser(int uid) {
System.out.println("在oracle中的user表得到id为"+uid+"的一条数据");
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 interface Factory {
IUser createUser();
ILogin createLogin();
}
具体工厂(每种产品的具体工厂生产)
public class MysqlFactory implements Factory {
@Override
public IUser createUser() {
return new MysqlUser();
}
@Override
public ILogin createLogin() {
return new MysqlLogin();
}
}
public class OracleFactory implements Factory {
@Override
public IUser createUser() {
return new OracleUser();
}
@Override
public ILogin createLogin() {
return new OracleLogin();
}
}
使用方(使用方只通过一个具体的工厂就可以获取到对应的实例对象)
public class Client {
public static void main(String[] args) {
User user=new User();
Login login = new Login();
Factory factory = new OracleFactory();
IUser iUser = factory.createUser();
iUser.getUser(1);
iUser.insert(user);
ILogin iLogin = factory.createLogin();
iLogin.getLogin(1);
iLogin.insert(login);
}
}
抽象工厂与工厂方法模式的区别在于:抽象工厂是可以生产多个产品的,例如 MysqlFactory 里可以生产 MysqlUser 以及 MysqlLogin 两个产品,而这两个产品又是属于一个系列的,因为它们都是属于MySQL数据库的表。而工厂方法模式则只能生产一个产品,例如之前的 MysqlFactory 里就只可以生产一个 MysqlUser 产品
优点:抽象工厂模式最大的好处是易于交换产品系列,由于具体工厂类,例如 IFactory factory=new OracleFactory();
,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易;抽象工厂模式的另一个好处就是它让具体的创建实例过程与客户端分离
缺点:如果你的需求来自增加功能,比如增加Login表,就有点太烦了。首先需要增加 ILogin,mysqlLogin,oracleLogin。 然后我们还要去修改工厂类: sqlFactory, mysqlFactory, oracleFactory 才可以实现,需要修改三个类,实在是有点麻烦