学习最好的方法还是得通过笔记和代码。所以今天继续学习工厂模式和策略模式。

简单工厂模式

工厂模式很多人比较熟悉,之前很多地方都能看到工厂模式。之前一直以为工厂模式很简单,所以就没有认真的去学习这个模式,没有去了解这个模式的精髓。今天就好好学习下。

什么是简单工厂模式?

工厂模式就是把创建对象的过程交给工厂类去做,而不是由我们需要用对象的人去创建,我们只管使用,不管这个对象是怎样创建出来的。

为什么使用简单工厂模式?

看个例子,例如现在有个交通工具接口 里面有个移动方法

public interface Vehicle {
void move();
}

拥有三个实现类,分别是自动车,汽车,公交汽车。

public class Bicycle implements Vehicle {
@Override
public void move() {
System.out.println("使用自定车出行");
}
}

public class Car implements Vehicle{
@Override
public void move() {
System.out.println("坐小轿车出行");
}
}

public class Bus implements Vehicle{
@Override
public void move() {
System.out.println("坐公交车出行");
}
}

假设现在我们需要骑汽车车出行,最简便的方法应该就是直接创建一个自行车对象然后进行嗲用move方法,例如这样:

public static void main(String[] args) {
Vehicle bicycle = new Bicycle();
bicycle.move();
}

这样是能够成功创建自行车对象的,但是现在自行车对象被修改了,创建自行车对象需要额外添加一个brand参数标识这个自行车的品牌。现在如果需要获取自行车对象可能第一时间想到就是修改一下创建Bicycle的代码,传入参数就好了。

public class Bicycle implements Vehicle {
private String brand;

public Bicycle(String brand){
this.brand = brand;
}

@Override
public void move() {
System.out.println("使用自定车出行");
}

public static void main(String[] args) {
Vehicle bicycle = new Bicycle("凤凰牌");
bicycle.move();
}
}

像上面这样很简单就实现了,但是如果一个程序中很多地方用到了Bicycle对象,那岂不是每个地方都要去修改它创建Bicycle对象的代码,那样也太难维护了吧。而且我们使用Bicycle对象根本不关系创建它需要什么东西,你只要能给我一个Bicycle对象就行,所以就出现了工厂模式。

工厂模式的使用

创建一个工厂类

public class VehicleFactory {
public static Vehicle getVehicle(String name){
Vehicle vehicle = null;
switch (name){
case "自行车":
vehicle = new Bicycle();
break;
case "汽车":
vehicle = new Car();
break;
case "公共汽车":
vehicle = new Bus();
break;
}
return vehicle;
}
}

现在我们获取一个自行车对象可以这样获取

public static void main(String[] args) {
Vehicle bicycle = VehicleFactory.getVehicle("自行车");
bicycle.move();
}

而如果现在创建自行车对象时需要添加一个brand参数的时候我们根本不需要在每个使用自行车对象的地方都传入brand参数,我们只需要在VehicleFactory工厂类中修改一下工厂类的代码就可以了。使用工厂模式降低了耦合度,因为使用自行车对象的人根本不管你自行车是怎么创建出来的,你只要能给我一个自行车对象就行,所以创建自行车的过程完全可以交给工厂去做。

工厂模式UML图

策略模式和工厂模式区别_工厂模式

 

策略模式

先看下策略模式的定义:

它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不好影响到使用算法的客户。

大概意思就是一个对象由于实例化不同的策略,所以最终在调用这个对象的统一方法的所获得的结果不不同,具体看代码。

还是上面的交通工具接口和三个实现类自行车,汽车,公共汽车。按理来说出行的不应该是交通工具,而应该是人吧,所以现在重新创建一个人的类,在人的类里面有一个交通工具引用,然后使用交通工具去出行。

public class Person {
private Vehicle vehicle;
private Person(Vehicle vehicle){
this.vehicle = vehicle;
}

/**
* 旅行方法
*/
public void travel(){
this.vehicle.move();
}
}

运行代码:

public static void main(String[] args) {
Person person = new Person(new Bicycle());
person.travel();

person = new Person(new Bus());
person.travel();
}

运行结果:

策略模式和工厂模式区别_工厂模式_02

可以看到由于选择的策略(Vehicle)不同,会导致运行的结果不同。

有人会说我直接调用自行车对象或公交车对象的方法不也可以有同样的运行结果吗?其实这里应该用到面向对象的概念,因为交通工具应该是人可以选择的。策略模式是一种定义一系列算法的方法,从概念上来看,所有的这些方法都是相同的工作,例如各种交通工具的根本作用不就是出行吗,只是实现不同,它可以以相同的方法调用所有的算法,例如上面的this.vehicle.move();.而且使用策略模式扩展性很好,增加一个策略,就多增加一个类就好了。

其实策略模式就是一个算法接口(Vehicle),多个算法实现(Bicycle,Bus,Car),和一个上下文(Person)。

策略模式UML图

策略模式和工厂模式区别_工厂类_03

其实现在看这个策略模式UML会发现一个问题,如果自行车类修改了怎么办?其实很简单,把策略模式和简单工厂模式结合使用就可以了,改写Person如下

public class Person {
private Vehicle vehicle;
private Person(String name){
switch (name){
case "自行车":
vehicle = new Bicycle();
break;
case "汽车":
vehicle = new Car();
break;
case "公共汽车":
vehicle = new Bus();
break;
}
}

/**
* 旅行方法
*/
public void travel(){
this.vehicle.move();
}
}

public static void main(String[] args) {
Person person = new Person("自行车");
person.travel();

person = new Person("公共汽车");
person.travel();
}

策略模式和工厂模式结合后还可以避免用户看到实际真正的策略类。具体策略模式和工厂模式需不需要结合还是看个人需求吧。

 

工厂方法模式

简单工厂模式最大的优点就是工程类中包含了必要的逻辑判断,根据用户的选择条件实例化相关的类,对于用户来说,去除了与具体产品的依赖。但是简单工厂模式有个缺陷。例如上面的例子我们需要增加一个新的交通工具,例如火车,那么我们必须创建一个火车类实现交通工具接口后还要重新去修改工厂类的swtch语句添加一个分支选项。设计模式有个原则就是开放封闭原则。而上面的做法就违背了这个原则。所有工厂模式就来了。

工厂模式的定义

定义一个用户创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

具体看代码:

创建一个工厂接口

public interface VehicleFactory2 {
Vehicle getVehicle();
}

然后像我们之前需要获取某种交通工具的方式改成分别写一个工厂类去实现这个接口,然后这个工厂类去创建具体的交通工具。

public class BicycleFactory implements VehicleFactory2 {
@Override
public Vehicle getVehicle() {
return new Bicycle();
}
}

// 公共汽车工厂类
public class BusFactory implements VehicleFactory2 {
@Override
public Vehicle getVehicle() {
return new Bus();
}
}

// 汽车类类似.......

我们现在再创建自行车对象和公共汽车对象就可以使用下面的方法

public static void main(String[] args) {
// 根据自行车工厂创建自行车
BicycleFactory bicycleFactory = new BicycleFactory();
Vehicle bicycle = bicycleFactory.getVehicle();
bicycle.move();
// 根据公共汽车工厂创建公共汽车
BusFactory busFactory = new BusFactory();
Vehicle bus = busFactory.getVehicle();
bus.move();
}

如果需要添加一个交通工具火车只需要创建一个火车类实现交通工具接口,再创建一个火车工厂实现交通工具工厂。这也就不用修改原来的代码就可以增加一个交通工具,符合了开放封闭原则。

工厂方法模式UML图

策略模式和工厂模式区别_策略模式_04

优缺点

工厂方法模式是简单工厂模式的进一步抽象和推广,由于使用了多态,工厂方法模式保持了简单工厂模式的有点,而且克服了它的缺点。但缺点是每加一个产品就多多加一个产品工厂类,增加了额外的开发量。

 

总结

简单来说两者工厂模式都是可以让使用对象的人去避免创建对象,工厂把对象给你了,你只管使用就可以了,而不必管这些对象究竟如何创建及如何组织的。工厂模式是可以配合反射来使用,这个以后学到再写吧。

策略模式就是根据用户提供的策略,在不同的场景中,该行为有不同的实现算法。策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。缺点是用户必须知道所有的策略类,可以通过和工厂模式来结合使用,不过也有弊端,并且每个策略都需要一个策略类,策略一多类也就非常多了。以前使用DBUtils时候传入不同的参数然后就可以有不同的封装方式返回object或者list就是就是的策略模式。