很久没有写技术博客了,最近太忙,再加上家里面的杂事儿太多,导致最近整个人都是不在状态,不过不管怎么说,该更新的博客,还是需要更新的,上一篇吐槽了最近项目重构优化的事情,也说了用了一些相关的设计模式,所以呢,我就是打算开始更新一部分我所熟悉的设计模式。
设计模式的更新,我打算分成五个阶段,第一个阶段呢,我打算先更新常用的单例、工厂、模板、代理这几种设计模式,因为这几种设计模式我相对来说比较熟,而且真正项目中使用过的,将几种设计模式讲过之后,我就是讲一些相关设计模式在常用框架或者工具类中的使用,加深我们的印象。
讲解设计模式呢,我就不关公面前耍大刀了,我打算完全按照《设计模式之禅》上面的来,这本书是我入门设计模式的书,买了好几年,但是就零零散散翻过一部分,之前代码重构的时候看过一丢丢,但是还是没有看完,这次就是趁着写博客的机会,把它从头到尾搞一遍吧。
好了,废话不多说,咱们现在开始第一阶段单例、工厂设计模式的讲解。
单例
单例的实现,现在网上相关的博客,也是非常多,所以我这边呢,也就是给出一个最简单的一种,其他的不多说,直接上代码吧,我想大家肯定是能够看懂的:
单例类Logger :
/***
* @desc 单例
* @author Aby
* @date 2020/07/25
*/
public class Logger {
private static final Logger logger = new Logger();
private Logger() {
}
public static Logger getInstance() {
return logger;
}
}
测试类App :
/***
* @desc 测试单例
* @author Aby
* @date 2020/07/25
*/
public class App {
public static void main(String[] args) {
Logger logger = Logger.getInstance();
Logger logger2 = Logger.getInstance();
System.out.println(logger == logger2);
}
}
好了,单例的代码已经写完了,其实就是私有了一个无参构造器,然后在类初始化的时候,就进行创建,并且提供一个静态方法,获取创建的对象即可,因为只初始化一次,所以是能够保证是单例的。
不过上面的这种写法,其实真正的想破解还是有方法的,不过那些不在咱们的考虑范围之内。
我提供的这个单例只是最简单最基础的一种,现在其实网上有各种各样的单例写法,大家有空也可以看看,对于工作的话,大多数时候其实也够用了,不过面试的时候可能会考你各种单例的实现模式吧,这一点儿需要关注一下。
好了,单例的讲完了,接下来咱们开始讲解一下相关的工厂模式。
工厂模式
工厂模式按照我们常用的,一般来说是分成普通工厂和抽象工厂,咱们先从普通工厂模式进行讲解。
普通工厂模式
假如说现在一个玩具公司,接到了一批玩具的订单,这批订单呢,总共是要生产两种玩具,一种是猴子,一种是小狗,其中呀,猴子是吱吱叫,小狗是汪汪叫,那么按照我们的普通工厂模式的话,定义相关的类就是如下的形式:
首先,玩具接口类IToy:
/***
* @desc 玩具类接口
* @author Aby
* @date 2020/07/25
*/
public interface IToy {
/***
* 玩具叫
*/
void getCry();
}
猴子的实现类MonkeyToy:
/***
* @desc 猴子的实现类
* @author Aby
* @date 2020/07/25
*/
public class MonkeyToy implements IToy {
@Override
public void getCry() {
System.out.println("猴子吱吱叫");
}
}
小狗的实现类DogToy:
/***
* @desc 小狗的实现类
* @author Aby
* @date 2020/07/25
*/
public class DogToy implements IToy {
@Override
public void getCry() {
System.out.println("小狗汪汪叫");
}
}
工厂接口AbstractToyFactory:
/***
* @desc 工厂生成
* @author Aby
* @date 2020/07/25
*/
public abstract class AbstractToyFactory {
/**
* @param c 实现了T泛型接口的子类
* @param <T> 泛型限制
* @return 返回对应的实现
*/
public abstract <T extends IToy> T createToy(Class<T> c);
}
工厂实现类ToyFactory:
/***
* @desc 具体工厂
* @author Aby
* @date 2020/07/25
*/
public class ToyFactory extends AbstractToyFactory {
@Override
public <T extends IToy> T createToy(Class<T> c) {
//定义一个玩具
IToy toy = null;
try {
//产生一个玩具
toy = (T) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
System.out.println("生成玩具失败!");
}
return (T) toy;
}
}
测试类CommonApp:
public class CommonApp {
public static void main(String[] args) {
AbstractToyFactory factory = new ToyFactory();
MonkeyToy monkeyToy = factory.createToy(MonkeyToy.class);
monkeyToy.getCry();
DogToy dogToy = factory.createToy(DogToy.class);
dogToy.getCry();
}
}
好了,执行测试类,能够打印出对应的玩具的叫声,咱们的普通工厂也实现完成了。
其实普通工厂模式,咱们基本上写代码用到的很多,特别是产品类的实现,就像我最近做的库存一样,都是属于备件,但是细分的话,又是不少种,这次优化代码的时候,就是用到了这一点儿。
抽象工厂模式
假如说玩具厂猴子玩具和小狗玩具,生产了一半了,因为产品做工质量非常高,现在公司又追加了一笔订单,还是生产猴子玩具和小狗玩具,但是呀,这一次的玩具要求具备不同的颜色,普通工厂模式的时候,因为没管颜色,都是统一的配色,但是现在需要有红色和黄色的了,那么按照上面的普通工厂模式的时候,我们肯定是需要在IToy接口新增对应的方法,然后修改对应的实现类,然后将相关联的都进行修改。
这种方式可以吗?其实是可以的,完成我们的目标完全是没什么问题的,但是假如说之后玩具又追加了其他的一系列的唱、跳、Rap的功能,我们还这么改吗?伴随着项目的运行,这种改动涉及的范围越来越广,也越来越没有保障,所以才出现了抽象工厂模式,具体的实现如下所示:
首先,玩具接口类IToy改造如下:
/***
* @desc 玩具类接口
* @author Aby
* @date 2020/07/25
*/
public interface IToy {
/***
* 玩具叫
*/
void getCry();
/***
* 玩具的颜色
*/
void getColor();
}
猴子类MonkeyToy改造如下:
/***
* @desc 猴子的实现类
* @author Aby
* @date 2020/07/25
*/
public abstract class MonkeyToy implements IToy {
@Override
public void getCry() {
System.out.println("猴子吱吱叫");
}
}
小狗类DogToy 改造如下:
/***
* @desc 小狗的实现类
* @author Aby
* @date 2020/07/25
*/
public abstract class DogToy implements IToy {
@Override
public void getCry() {
System.out.println("小狗汪汪叫");
}
}
工厂接口AbstractToyFactory保持不变:
/***
* @desc 工厂生成
* @author Aby
* @date 2020/07/25
*/
public abstract class AbstractToyFactory {
/**
* @param c 实现了T泛型接口的子类
* @param <T> 泛型限制
* @return 返回对应的实现
*/
public abstract <T extends IToy> T createToy(Class<T> c);
}
实现工厂类ToyFactory 保持不变:
/***
* @desc 具体工厂
* @author Aby
* @date 2020/07/25
*/
public class ToyFactory extends AbstractToyFactory {
@Override
public <T extends IToy> T createToy(Class<T> c) {
//定义一个玩具
IToy toy = null;
try {
//产生一个玩具
toy = (T) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
System.out.println("生成玩具失败!");
}
return (T) toy;
}
}
紧接着,我们需要创建对应的黄色猴子玩具类YellowMonkeyToy了:
/***
* @desc 黄色猴子玩具类
* @author Aby
* @date 2020/07/25
*/
public class YellowMonkeyToy extends MonkeyToy {
@Override
public void getColor() {
System.out.println("黄色猴子玩具");
}
}
红色猴子玩具类RedMonkeyToy了:
/***
* @desc 红色猴子玩具类
* @author Aby
* @date 2020/07/25
*/
public class RedMonkeyToy extends MonkeyToy {
@Override
public void getColor() {
System.out.println("红色猴子玩具");
}
}
然后是黄色小狗玩具类YellowDogToy:
/***
* @desc 黄色小狗玩具类
* @author Aby
* @date 2020/07/25
*/
public class YellowDogToy extends DogToy {
@Override
public void getColor() {
System.out.println("黄色小狗玩具");
}
}
红色小狗玩具类RedDogToy:
/***
* @desc 红色小狗玩具类
* @author Aby
* @date 2020/07/25
*/
public class RedDogToy extends DogToy {
@Override
public void getColor() {
System.out.println("红色小狗玩具");
}
}
好了,定义完成,接下来就是看看我们的测试类App了:
public class App {
public static void main(String[] args) {
AbstractToyFactory factory = new ToyFactory();
MonkeyToy yellowMonkeyToy = factory.createToy(YellowMonkeyToy.class);
yellowMonkeyToy.getColor();
yellowMonkeyToy.getCry();
MonkeyToy redMonkeyToy = factory.createToy(RedMonkeyToy.class);
redMonkeyToy.getColor();
redMonkeyToy.getCry();
DogToy yellowDogToy = factory.createToy(YellowDogToy.class);
yellowDogToy.getColor();
yellowDogToy.getCry();
DogToy redDogToy = factory.createToy(RedDogToy.class);
redDogToy.getColor();
redDogToy.getCry();
}
}
好了,执行对应的测试类,我们能够看到我们成功生成出符合要求的玩具,而且不管以后要生成什么颜色的玩具,只需要新增对应的产品类就成了,相比起普通工厂模式,抽象工厂模式相比来说原有逻辑改动较小,可扩展性也相对高一点儿,在项目中应用的话,相对来说便于以后扩展。
好了,这次的设计模式就讲到这里,下一讲咱们就是开始讲讲模板和代理两种设计模式。