设计模式文章陆续更新
java单例模式
java代理模式
java状态模式
工业发展到现在很多东西都已经分工十分明显,如要制作一辆特斯拉汽车,产商会将其分工给几个几条生产线来完成,A线生产车罩,B线生产引擎,C线生产底盘等等...
而对于程序猿来说代码的发展也是千变万化,从 面相过程到面试对象,再到设计模式...
工厂设计模式的设计思想也是遵循着面向对象设计的基本原则来拓展的,面向过程中是没有的.
在Java面向对象编程中,我们通常会new操作符来构造对象实例,但是在一些情况下,直接new生产对象会给项目带来一些问题,如果项目中很多地方都需要使用到该对象A,那么你需要写很多A a=new A();
这样代码有坏味道,耦合性强,对以后的重构会艰难重重.
怎么解决?
如果用工厂模式,我们关注的就只是工厂内的代码,调用者主需要知道工厂提供的接口,可以做到只修改一个地方,其他代码都不动,降低了耦合性.
下面我们一起来分析下:工厂模式的类型;复合模式的应用;工厂方法由来...
什么是工厂模式?
简单点说就是帮我们解决new的问题,我们可以将工厂模式分为两大角色调用者与创建者.
一般情况下调用者与创建者之间关系会很密切,包括要知道创建者整个过程.
使用工厂模式可以有效的降低两者直接的关系,从而解耦.
- 实例化对象
用工厂方法代替new操作,从而简化实例化过程. - 统一管理和控制
对实现类通过工厂来管理和控制,从而将调用者跟我们的实现类解耦.
工厂模式的分类
工厂模式是一个大类,在其下面还分为:
- 简单工厂(静态工厂)
- 工厂方法
- 抽象工厂
实际案例
案例: 我要制造一辆高级BYD轿车.代码中如何实现?
分析下思路:
- 对象: 我,轿车
- 行为: 制造,运行
一般情况写法 (使用简单,耦合性高)
通常情况下我们要创建某个对象,就直接new出来即可,再根据对象特性传入参数,最后调用其特有方法.
示例代码:
创建者
public class Byd implements Car {
public Byd(String level) {
System.out.println("生产"+level+"BYD汽车");
}
public void run() {
System.out.println("BYD is running...");
}
}
调用者
public class Client {
public static void main(String[] args) {
Byd byd = new Byd("byd");
byd.run();
}
}
输出:
生产 高级 BYD汽车
BYD is running...
问题思考
这样写简单而粗暴,调用者需要知道对象有什么参数,调用什么方法,当参数或者方法多的时候,这个过程是繁琐的.还有上面提到过的频繁调用.我们可以使用工厂模式来解决该问题.
简单工厂/静态工厂 (使用简单,耦合性一般)
生产同一等级结构中的任意产品.(对于添加新产品需要修改已有代码)
案例:使用简单工厂对上面案例进行优化.
示例代码:
创建者
/**
* 轿车抽象接口
*/
public interface Car {
void run();
}
/**
* BYD轿车实现类
*/
public class Byd implements Car {
public void run() {
System.out.println("BYD is running...");
}
}
/**
* 下面使用了两种方式来生产实体对象
*
* 简单工厂有个问题: 对于新增的产品无法进行动态修改,这有点违背了ocp原则
*
* @author relicemxd
*/
public class SimpleFactory {
// 静态方法方式实现
public static Car CreateByd() {
return new Byd();
}
// 通过判断的方式实现
public static Car Creater(String car) {
if (car.equals("byd")) {
return new Byd();
} else {
return null;
}
}
}
调用者
/**
* @author relicemxd
* 调用者只需安排工厂来生产BYD,而不用知道其具体的生产过程.从而简化了创建者与调用者之间的
* 交互流程
*/
public class Client {
private static Car car;
public static void main(String[] args) {
Car byd = SimpleFactory.CreateByd();
car = SimpleFactory.Creater("byd");
byd.run();
}
}
输出:
BYD is running...
简单工厂UML图:
问题思考
从上面可以看出工厂类一般使用static方法,因此简单工厂也叫静态工厂,通过接收不同的参数return不通的实例对象.调用者只需要知道Factory类与Car接口.
但是
简单工厂依旧存在一个问题,假如我现在需要创建一个BMW轿车,要怎么扩展呢?
需要修改Factory类的中原有的方法.这样有点违背了面向对象设计的OCP开闭原则.
工厂方法 (使用复杂,耦合性低)
用来生产同一登记结构中固定产品.(支持添加任意产品)
在简单的工厂中,我们需求的变动,需要涉及到原工厂中去,这样不符合OCP原则,因此对简单工厂的优化,就有了工厂方法模式,让开发者只需要处理业务代码.
案例:上面基础上,再创造另一种轿车(BMW).
示例代码:
创建者
与上面简单工厂还是有抽象Car接口和具体实现类BYD与BMW.这里就忽略相同的代码.
为不同工厂提取功能接口
public interface Factory {
Car createCar();
}
BMW和BYD都分开不同的工厂来制造
public class BmwFactory implements Factory {
public Car createCar() {
return new Bmw();
}
}
public class BydFactory implements Factory {
public Car createCar() {
return new Byd();
}
}
调用者
public class Client {
public static void main(String[] args) {
Car bmw = new BmwFactory().createCar();
Car byd = new BydFactory().createCar();
bmw.run();
byd.run();
}
}
输出:
BYD is running...
BMW is running...
工厂方法UML图:
问题思考
简单工厂与工厂方法最大的不同在于,前者只有一个工厂类(对于一个项目或者一个独立模块而言),而工厂方法模式有一组实现了相同接口的工厂类.
工厂方法避免了简单工厂不完全满足OCP原则的缺点.
但是
也引出了另一些问题,每个工程类只能处理固定产品
,因为工厂类多了,整体代码量变复杂
,实践与理论总有一点差距,在项目中使用比较多的还是简单工厂.
需求变化
此时如果我需要生产出轿车的引擎,轮胎等具体部件,那么使用简单工厂或者工厂方法都会十分麻烦,思考下引擎有高配,低配,轮胎也有普通,高级.
抽象工厂 (使用复杂,耦合性高)
用来生产不同产品族的全部产品.(对于增加新的产品,无能为力,支持添加产品族)
抽象工厂不同于简单工厂与工厂方法,他是对一个族群的扩展.
它也是工厂方法模式的升级版本,在有多个业务品种,业务分类时,通过抽象工厂生产需要的对象是一种非常好的解决方式.
案例:生产高低端两种不同配置的BYD汽车
示例代码:
因为接口比较多,为了方便阅读,我通过内部类实现.
创建者:
生产引擎
public interface Engine {
void engine();
}
class HighEngine implements Engine {
public void engine() {
System.out.println("生产高端引擎...");
}
}
class LowEngine implements Engine {
public void engine() {
System.out.println("生产低端引擎...");
}
}
生产轮胎
public interface Tyre {
void tyre();
}
class HighTyre implements Tyre {
public void tyre() {
System.out.println("生产高速轮胎....");
}
}
class LowTyre implements Tyre {
public void tyre() {
System.out.println("生产低速轮胎....");
}
}
汽车工厂
/**
* @author relicemxd
* 汽车工厂接口,用户需要什么类型的产品族就调用什么类型的工厂.
*/
public interface CarFactory {
//制作引擎工厂
Engine createEngine();
//制作轮胎工厂
Tyre createTyre();
//开始生产
void make();
}
/**
* 高端工厂,生产高端汽车
*/
class HighCarFactory implements CarFactory {
@Override
public Engine createEngine() {
return new HighEngine();
}
@Override
public Tyre createTyre() {
return new HighTyre();
}
@Override
public void make() {
System.out.println("开始制造高端汽车...");
}
}
/**
* 低端工厂,生产低端汽车
*/
class LowCarFactory implements CarFactory {
@Override
public Engine createEngine() {
return new LowEngine();
}
@Override
public Tyre createTyre() {
return new LowTyre();
}
@Override
public void make() {
System.out.println("开始制造低端汽车...");
}
}
调用者:
public class Client {
public static void main(String[] args) {
//高端车工厂
HighCarFactory highCarFactory = new HighCarFactory();
Engine engine = highCarFactory.createEngine();
engine.engine();
Tyre tyre = highCarFactory.createTyre();
tyre.tyre();
highCarFactory.make();
}
}
输出:
生产高端引擎...
生产高速轮胎....
开始制造高端汽车...
抽象工厂UML图:
问题思考
在实际项目中抽象工厂的使用率很低,但是面试中会经常遇到,了解他的思想也是有必要的.
工厂模式与单例
在实际项目中一般都会有几种设计模式结合在一起,如工厂模式与单例最为常见.
/**
* 单例模式与工厂模式结合使用
*
* @author relicemxd
*/
public class SingleSimpleFactory {
// 通过判断的方式实现
public static Car Creater(String car) {
if (car.equals("byd")) {
// return new Byd();
return Byd.INSTANCE;
} else {
return null;
}
}
/**
* 这里使用了enum作为单例
*/
enum Byd implements Car {
INSTANCE;
public void run() {
System.out.println("BYD is running...");
}
}
}
总结
- 简单工厂(静态工厂)
- 尽管某种程度上不太符合面向对象设计原则,但是实际使用最多.
- 工厂方法
- 尽管是对简单工厂的一个优化,在不修改已有类的前提下,通过添加新的工程类来实现扩展,但是多出了很多类,有点不太实际.
- 抽象工厂
- 这个是对工厂方法的一个升级,可以添加产品族,但是不可以添加其他产品,一般在面试中会遇到,使用率不高.