Java设计模式之工厂模式分析【简单工厂、工厂方法、抽象工厂】
作者:aronykl 发布时间:2021-07-07 21:11:57
本文实例讲述了Java设计模式之工厂模式。分享给大家供大家参考,具体如下:
一、 简单工厂
先来思考一个问题。我们平时写程序时,会有这种情况,A对象里面需要调用B对象的方法,这时我们使用的一般是new关键字来创建一个B实例,然后调用B实例的方法。这种做法的坏处在于:A类的方法实现直接调用了B类的类名(这种方式也被称为硬编码耦合),一旦系统需要重构:需要使用C类来代替B类时,程序就不得不修改A类代码,如果应用中有100个或者10000个类以硬编码方式耦合了B类,则需要修改100个、10000个地方,这显然是一种非常可怕的事情。
换一个角度来看这个问题:对已A对象而言,它只需要调用B对象的方法,并不关心B对象的实现、创建过程,考虑让B类实现一个IB接口,而A类只需要与IB接口耦合——A类并不直接使用new关键字来创建B实例,而是重新定义一个工厂类:IBFactory,由该工厂类负责创建IB实例,而A类用过调用IBFactory工厂的方法来得到IB的实例。通过以上设计:需要使用C类代替B类,则只需要让C类也实现IB接口,并改写IBFactory工厂中创建IB实例的实现代码,让该工厂产生C实例即可。这种将多个类对象交给工厂类来生成的设计方式叫做简单工厂模式。
以下是简单工厂模式的代码:
/**
* 简单工厂模式
*
* 需要工厂生产的对象实例所实现的共同的接口
* 发型接口
* @author Administrator
*
*/
public interface Hair {
/**
* 画发型
*/
public void draw();
}
/**
* 左偏分发型
* @author Administrator
*
*/
public class LeftHair implements Hair {
@Override
public void draw() {
System.out.println("----------------画左偏分发型-----------------");
}
}
/**
* 右偏分发型
* @author Administrator
*
*/
public class RightHair implements Hair {
@Override
public void draw() {
System.out.println("-----------------画右偏分发型------------------");
}
}
/**
* 生产发型的工厂
* 要生产什么发型 只需在这里改就行了
* @author Administrator
*
*/
public class HairFactory {
public Hair getHair() {
return new LeftHair();
//return new RightHair();
}
}
/**
* 客户端测试类
* @author Administrator
*
*/
public class HairTest {
public static void main(String[] args) {
HairFactory factory = new HairFactory();
Hair hair = factory.getHair();
hair.draw();
}
}
可以看到,如果想把HairTest里面生成的LeftHair改成RightHair,只需修改HairFactory里面getHair方法的实现即可。
使用简单工厂模式的优势在于:让对象的调用者和对象的创建过程分离,当对象调用者需要对象时,直接向工厂请求即可,从而避免了对象的调用者与对象实现类以硬编码方式耦合,以提高系统的可维护性、可扩展性。当然,工厂模式也有一个小小的缺陷,当产品修改时,工厂类也要做相应的修改,此处可使用策略模式进行解决,下面是代码。
public interface HairBuilder {
/**
* 制造发型
* @return
*/
public Hair getHair();
}
public class LeftHairBuilder implements HairBuilder {
@Override
public Hair getHair() {
return new LeftHair();
}
}
public class RightHairBuilder implements HairBuilder {
@Override
public Hair getHair() {
return new RightHair();
}
}
public class HairFactory {
private HairBuilder hairBuilder;
public HairFactory(HairBuilder hairBuilder) {
this.hairBuilder = hairBuilder;
}
public void setHairBuilder(HairBuilder hairBuilder) {
this.hairBuilder = hairBuilder;
}
public Hair getHair() {
return hairBuilder.getHair();
}
}
public class HairTest {
public static void main(String[] args) {
// HairBuilder builder = new LeftHairBuilder();
HairBuilder builder = new RightHairBuilder();
HairFactory factory = new HairFactory(builder);
Hair hair = factory.getHair();
hair.draw();
}
}
这种做法的好处是无需再去修改工厂类,将工厂里面的创建对量逻辑根据不同的策略抽象出来,程序需要创建什么对象,只需网工厂中传入相应的builder即可。
二、工厂方法
在简单工厂模式中,系统使用工厂类生产所有产品实例,且该工厂类决定生产哪个类的实例,即工厂类负责所有的逻辑判断、实例创建等工作。
如果不想再工厂类中进行逻辑判断,程序可以为不同的产品类提供不同的工厂,不同的工厂类生产不同的产品,无需再工厂类中进行复杂的逻辑判断。这就有点类似于上面的简单工厂模式结合策略模式,不同的是前者只有一个工厂,后者需要有多个工厂。下面是工厂方法模式的代码。
/**
* 工厂方法模式
* 需要工厂生产的对象实例所实现的共同的接口
* @author Administrator
*
*/
public interface Person {
public void drawPerson();
}
public class Man implements Person {
@Override
public void drawPerson() {
System.out.println("---------------------draw a man--------------------");
}
}
public class Women implements Person {
@Override
public void drawPerson() {
System.out.println("--------------------draw a women---------------------");
}
}
/**
* 生产人的工厂
* @author Administrator
*
*/
public interface PersonFactory {
//生产人
public Person getPerson();
}
/**
* 生产man的工厂
* @author Administrator
*
*/
public class ManFactory implements PersonFactory {
@Override
public Person getPerson() {
return new Man();
}
}
/**
* 声场women的工厂
* @author Administrator
*
*/
public class WomenFactory implements PersonFactory {
@Override
public Person getPerson() {
return new Women();
}
}
/**
* 客户端测试类
* @author Administrator
*
*/
public class PersonTest {
public static void main(String[] args) {
// PersonFactory factory = new ManFactory();
PersonFactory factory = new WomenFactory();
Person person = factory.getPerson();
person.drawPerson();
}
}
这种的典型的特点就是在客户端代码中根据不同的工厂生产其对应的产品,不必把复杂的逻辑都放在工厂类里面判断。这种实现有一个很明显的缺陷,就是客户端与工厂类进行了耦合。
三、抽象工厂
采用上面的工厂方法的设计架构,客户端代码成功与被调用对象的实现类分离,但带来了另一种耦合:客户端代码与不同的工厂类耦合。为了解决这种耦合的问题,考虑在增加一个工厂类,用来生成工厂实例,实现生产产品的工厂与客户端分离,这种设计方式被称为抽象工厂模式。下面是抽象工厂模式的代码
/**
* 抽象工厂模式
* 生产PersonFactory的工厂
* @author Administrator
*
*/
public class PersonFactoryFactory {
public static PersonFactory getPersonFactory(String type) {
if(type.equalsIgnoreCase("man")) {
return new ManFactory();
} else {
return new WomenFactory();
}
}
}
/**
* 客户端测试类
* @author Administrator
*
*/
public class PersonTest {
public static void main(String[] args) {
PersonFactory factory = PersonFactoryFactory.getPersonFactory("man");
Person person = factory.getPerson();
person.drawPerson();
}
}
更多java相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》
希望本文所述对大家java程序设计有所帮助。
来源:https://blog.csdn.net/zw19910924/article/details/52373892
猜你喜欢
- Java代码1. ReentrantLock加锁阻塞,一个condition对应一个线程,以便于唤醒时使用该condition一定会唤醒该线
- SpringBoot 配置SwaggerUI 访问404的小坑。在学习SpringBoot构建Restful API的时候遇到了一个小坑,配
- .NETCORE 中的 Generic Host本文以自己在工作中学习和使用.net core generic-host 作一个总结。前言在
- 引言 批量下载思路,首先前端发送下载请求,携带必要参数,
- 首先我们看看为什么需要对象复制?为什么需要对象复制如上,是我们平时开发中最常见的三层MVC架构模型,编辑操作时Controller层接收到前
- 前言兄弟们,刚刚又给seata社区修了一个BUG,有用户提了issue反应TransactionHook在某些情况下不会被调用:相关issu
- 前言本文讲解了在Spring 应用中创建Bean的多种方式,包括自动创建,以及手动创建注入方式,实际开发中可以根据业务场景选择合适的方案。方
- DrawingContext比较类似WinForm中的Graphics 类,是基础的绘图对象,用于绘制各种图形,它主要API有如下
- 公司的老项目要改造多租户,于是进入了大坑,本文写点遇到的坑以及解决方案,每次遇到问题在网上搜了好久,记录下来,防止以后忘掉。(一).方案网上
- 0 写在前面在实际工作中有一些地方需要用到截取字符串的方法,所以在此记录下截取字符串的几种方法。.substring()StringUtil
- watch机制Zookeeper watch是一种监听通知机制,可以随时监听一些数据的变化,从而实现数据的及时性。Zookeeper所有的读
- 回顾Tomcat8打法先回顾下之前Tomcat789的打法这里先抛开 7 8之间的区别, 在8中,最后add到filterchain的都是一
- 1、理论一般如果想将类注册到spring容器,让spring来完成实例化,常用方式如下:xml中通过bean节点来配置;使用@Service
- 需求:用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合;要按照总分从高到低进行排序分析:1.创建学生类 成员变
- 前言Java8 的新特性:Lambda表达式、强大的 Stream API、全新时间日期 API、ConcurrentHashMap、Met
- Zuul 简介Zuul 的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如 /api/admin 转发到到 Admin 服务,/a
- 问题描述ResultSet 表示 select 语句的查询结果集。ResultSet 对象具有指向其当前数据行的指针, 最初,指针被置于第一
- 本文实例分析了Java接口默认方法带来的问题。分享给大家供大家参考,具体如下:一 点睛Java 8中,如果一个类实现两个或多个接口,即“变相
- 前言ps命令的作用是显示进程信息的。|符号,是个管道符号,表示左右两边两个命令同时执行。grep命令是查找(Global Regular E
- Java8Stream流操作List去重根据属性去重整体去重使用distinctArrayList<LabelInfoDTO>