现在有一个发快递的流程要实现,如果用传统的方式实现,代码是下面这样
//快递抽象类
public abstract class Express {
private String name;
//快递下单,不同的快递需要在不同的网站下单,做成抽象
public abstract void placeAndOrder();
//取件方法
public void pickUp(){
System.out.println(name+"快递员来取件");
}
//发货方法
public void sendOut(){
System.out.println(name+"快递发出");
}
public void setName(String name){
this.name = name;
}
}
//顺丰快递
public class SFExpress extends Express{
public SFExpress(){
super.setName("顺丰");
}
@Override
public void placeAndOrder() {
System.out.println("在顺丰官网下单");
}
}
//京东快递
public class JDExpress extends Express{
public JDExpress(){
super.setName("京东");
}
@Override
public void placeAndOrder() {
System.out.println("在京东快递官网下单");
}
}
//快递订单类
public class ExpressOrder {
public ExpressOrder(String type) {
Express express = null;
if ("JD".equals(type)) {
express = new JDExpress();
} else if ("SF".equals(type)) {
express = new SFExpress();
}
//过程
express.placeAndOrder();
express.pickUp();
express.sendOut();
}
}
public class ExpressTest {
public static void main(String[] args) {
new ExpressOrder("SF");
System.out.println("_____________");
new ExpressOrder("JD");
}
}
运行测试类的结果
这样看起来是没有问题的,但是这样设计违反了开闭原则,即对扩展开放,对修改关闭。
在实际开发中,订单类可能不只有一个,如果要新增一个快递种类,需要改多处代码。
简单工厂模式
简易工厂模式属于创建型模式,是工厂模式的一种。简易工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,是工厂模式中最简单实用的模式
简易工厂模式:定义了一个创建对象的类,这个类用来封装实例化对象的代码,在开发中,当需要大量的创建某种对象,某类对象,某批对象时,就会使用到工厂模式
现在在上面的代码基础上加一个简单工厂类
//简单工厂
public class SimpleFactory {
public Express getExpress(String type){
Express express = null;
if ("JD".equals(type)) {
express = new JDExpress();
} else if ("SF".equals(type)) {
express = new SFExpress();
}
return express;
}
}
然后在订单类中聚合这个简单工厂类
//快递订单类
public class ExpressOrder {
private SimpleFactory simpleFactory = new SimpleFactory();
public ExpressOrder(String type){
Express express = simpleFactory.getExpress(type);
express.placeAndOrder();
express.pickUp();
express.sendOut();
}
}
然后使用测试类
public class ExpressTest {
public static void main(String[] args) {
new ExpressOrder("SF");
System.out.println("_____________");
new ExpressOrder("JD");
}
}
输出的结果还是一样的
这样一来,如果要新增一个新的快递类型,只需要在工厂类里面新增一句代码,而不需要每个订单类都要修改(如果有多个订单类)
如果把工厂类中的getExpress方法改成静态方法,在订单类中就可以直接类名调用,这样就变成了静态工厂模式
工厂方法模式
还是上面的寄快递需求,现在需求变了,京东和顺丰不止有快递还有物流,可能需要发京东快递或京东物流、顺丰快递或顺丰物流
这个时候可以考虑使用工厂方法模式
设计方案:将快递对象实例化的功能抽象成抽象方法,在不同的快递子类中具体实现
即定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
快递类不变,实现四个子类,如图
对象实例化方法放到订单类,做成抽象方法,由子类实现
//快递订单类
public abstract class ExpressOrder {
abstract Express getExpress(String type);
public ExpressOrder(String type){
Express express = getExpress(type); //抽象方法,由子类完成
express.placeAndOrder();
express.pickUp();
express.sendOut();
}
}
两个订单子类
//京东快递订单类
public class JDExpressOrder extends ExpressOrder{
public JDExpressOrder(String type) {
super(type);
}
@Override
Express getExpress(String type) {
Express express = null;
if("JD".equals(type)){
express = new JDExpress();
}else if("JDWL".equals(type)){
express = new JDExpressWL();
}
return express;
}
}
//顺丰快递订单类
public class SFExpressOrder extends ExpressOrder{
public SFExpressOrder(String type) {
super(type);
}
@Override
Express getExpress(String type) {
Express express = null;
if("SF".equals(type)){
express = new SFExpress();
}else if("SFWL".equals(type)){
express = new SFExpressWL();
}
return express;
}
}
测试类测试
public class ExpressTest {
public static void main(String[] args) {
new JDExpressOrder("JD");
System.out.println("_________________");
new JDExpressOrder("JDWL");
System.out.println("_________________");
new SFExpressOrder("SF");
System.out.println("_________________");
new SFExpressOrder("SFWL");
}
}
输出结果
抽象工厂模式
抽象工厂模式是把上面两种方法综合起来,工厂类使用接口,然后根据分类新建多个工厂子类。
public interface AbsFactory {
Express getExpress(String type);
}
public class JDFactory implements AbsFactory{
@Override
public Express getExpress(String type) {
Express express = null;
if("JD".equals(type)){
express = new JDExpress();
}else if("JDWL".equals(type)){
express = new JDExpressWL();
}
return express;
}
}
public class SFFactory implements AbsFactory{
@Override
public Express getExpress(String type) {
Express express = null;
if("SF".equals(type)){
express = new SFExpress();
}else if("SFWL".equals(type)){
express = new SFExpressWL();
}
return express;
}
}
然后在订单类中组合工厂类
//快递订单类
public class ExpressOrder {
AbsFactory factory;
public ExpressOrder(AbsFactory factory,String type){
Express express = factory.getExpress(type); //抽象方法,由子类完成
express.placeAndOrder();
express.pickUp();
express.sendOut();
}
}
测试
public class ExpressTest {
public static void main(String[] args) {
new ExpressOrder(new JDFactory(),"JD");
System.out.println("______________");
new ExpressOrder(new JDFactory(),"JDWL");
System.out.println("______________");
new ExpressOrder(new SFFactory(),"SF");
System.out.println("______________");
new ExpressOrder(new SFFactory(),"SFWL");
}
}
输出结果还是一样的
在jdk中哪里使用到了工厂模式呢,Calendar类(日历类)在创建的时候,使用静态方法getInstance,使用的是简单工厂模式
工厂模式的意义:将实例化对象的代码抽取出来,放到一个类中统一管理,达到和主项目的依赖关系解耦,提高项目的扩展性和维护性。
抽象工厂模式就遵循了八大原则中的依赖倒置原则,去依赖抽象而不是依赖细节