工厂模式

1|0基本介绍

  • 工厂模式:属于创建模式的一种,仔细划分的话,工厂模式大致分为三种,简单工厂模式、工厂方法模式以及抽象工厂模式。
  • 主要作用:创建对象时避免客户端直接暴露创建逻辑(解耦),而是通过一个公共的接口去创建对象。
  • 优点:①. 扩展性好,想增加产品,只要扩展相应工厂类即可。(也是缺点)②. 屏蔽产品的具体实现细节

 

2|0简单工厂模式

基于上图说的场景,我们了解所有的英雄和英雄皮肤都可以被购买,那么我们先定义一个接口让所有英雄和英雄皮肤遵循这个规则

public interface Hero { /** * 成功购买英雄 */ void buyHeroSuccess(); /** * 成功购买配套皮肤 */ void buySkinSuccess(); }

 

那么接下来我们开始定义不同的英雄,这里我们分别选 妲己、程咬金、后羿 作为示例

/** * 妲己 */ public class DaJi implements Hero { @Override public void buyHeroSuccess() { System.out.println("勇士,恭喜你获得了英雄-妲己!"); } @Override public void buySkinSuccess() { System.out.println("恭喜你获得了皮肤-热情桑巴"); } }
/** * 程咬金 */ public class ChengYaoJin implements Hero { @Override public void buyHeroSuccess() { System.out.println("勇士,恭喜你获得了英雄-程咬金!"); } @Override public void buySkinSuccess() { System.out.println("恭喜你获得了皮肤-爱与正义"); } }
/** * 后羿 */ public class HouYi implements Hero { @Override public void buyHeroSuccess() { System.out.println("勇士,恭喜你获得了英雄-后羿!"); } @Override public void buySkinSuccess() { System.out.println("恭喜你获得了皮肤-黄金射手座"); } }

 

上面我们一下子就定义了三个英雄,下面就可以开始简单工厂的核心了-工厂

既然是工厂模式,那么生产产品的时候(即创建类),由工厂统一管理,我们通过标签去决定生产什么样的产品

/** * 王者荣耀工厂(商城) */ public class HerosFactory { /** * 根据不同的标签生产不同的英雄 */ public Hero getDifferentHero(String heroType) { if("HouYi".equals(heroType)){ return new HouYi(); }else if("DaJi".equals(heroType)){ return new DaJi(); }else if("ChengYaoJin".equals(heroType)){ return new ChengYaoJin(); } return null; } }

 

写完了简单工厂的工厂类,我们可以写个测试方法测试一下

/** * 测试方法 */ public class TestFactory { public static void main(String[] args) { HerosFactory herosFactory = new HerosFactory(); Hero hero1 = herosFactory.getDifferentHero("DaJi"); hero1.buyHeroSuccess(); hero1.buySkinSuccess(); System.out.println("-----------------"); Hero hero2 = herosFactory.getDifferentHero("HouYi"); hero2.buyHeroSuccess(); hero2.buySkinSuccess(); } }

 

 

3|0工厂方法模式

我个人认为工厂方法模式是简单工厂模式的升级,我们先想想简单工厂模式最大的缺点是啥?

如果我想新增一个对象,那么我就需要扩展工厂类,即我需要去改工厂类的生产方法代码去增加一个标签

这么干,实际违背了 开闭原则-对外扩展开放,对内修改关闭
 
比较好的方案是什么呢?

再定义一个抽象的工厂类型的基类,让子类去实现该基类(也就是工厂与实例对象遥相呼应),可能这么说,还是有人不明白,上代码
 

首先英雄接口部分还是和简单工厂一致

public interface Hero { /** * 成功购买英雄 */ void buyHeroSuccess(); /** * 成功购买配套皮肤 */ void buySkinSuccess(); }

 

接着我们是已购买三个英雄,妲己、程咬金、后羿

/** * 妲己 */ public class DaJi implements Hero { @Override public void buyHeroSuccess() { System.out.println("勇士,恭喜你获得了英雄-妲己!"); } @Override public void buySkinSuccess() { System.out.println("恭喜你获得了皮肤-热情桑巴"); } }
/** * 程咬金 */ public class ChengYaoJin implements Hero { @Override public void buyHeroSuccess() { System.out.println("勇士,恭喜你获得了英雄-程咬金!"); } @Override public void buySkinSuccess() { System.out.println("恭喜你获得了皮肤-爱与正义"); } }
/** * 后羿 */ public class HouYi implements Hero { @Override public void buyHeroSuccess() { System.out.println("勇士,恭喜你获得了英雄-后羿!"); } @Override public void buySkinSuccess() { System.out.println("恭喜你获得了皮肤-黄金射手座"); } }

 

上述代码都是和简单工厂部分一致,针对我们说的问题,我们说 定义一个抽象的工厂类型的基类

/** * 工厂方法模式:(王者荣耀商城) */ public abstract class HeroFactory { protected abstract Hero productHero(); }

 

我们已经看到了,基类的抽象方法可以创建英雄,那么需要创建的子类工厂通过继承该基类就可以完成创建所需英雄的功能了

/** * 定义一个射手英雄工厂 */ public class ArrowFactory extends HeroFactory{ @Override protected Hero productHero() { return new HouYi(); } }
/** * 法师工厂 */ public class MageFactory extends HeroFactory{ @Override protected Hero productHero() { return new DaJi(); } }
/** * 坦克工厂 */ public class TanksFactory extends HeroFactory{ @Override protected Hero productHero() { return new ChengYaoJin(); } }

 

定义完三个工厂,我们再次进行测试

/** * 测试工厂方法模式 */ public class TestFatcoryMethod { public static void main(String[] args) { Hero hero1 = new ArrowFactory().productHero(); hero1.buyHeroSuccess(); hero1.buySkinSuccess(); System.out.println("------------"); Hero hero2 = new MageFactory().productHero(); hero2.buyHeroSuccess(); hero2.buySkinSuccess(); } }

 

4|0抽象工厂模式

抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态模式。(不然怎么叫抽象工厂)

其次抽象工厂是指当有多个抽象角色,使用一种工厂模式。抽象工厂可以向提供一个接口,使客户端在不指定产品的具体情况下,创建多个产品族中的对象。一个抽象工厂类,可以派生多个具体工厂类,每个具体的工厂类可以创建多个产品的实例。

工厂方法模式 是对 一个产品类型进行构建,而抽象工厂则针对的 是 多个产品类型的构建。
 
下面我们用代码去演绎抽象工厂模式:

之前说过王者荣耀商城中,可以买英雄和皮肤。按照面向对象的思想我们可以将英雄 和 皮肤 单独抽取,成为最顶层的接口。那么会有下面的代码:

//英雄的顶层接口 public interface Hero { void haveHero(); }

 

定义完第一个抽象角色,也就是英雄的顶层接口,接下来我们定义具体的实现

/** * 妲己 */ public class DaJiHero implements Hero { @Override public void haveHero() { System.out.println("勇士,恭喜你已获得-妲己"); } }
/** * 程咬金 */ public class ChengYaoJinHero implements Hero { @Override public void haveHero() { System.out.println("勇士,恭喜你已获得-程咬金"); } }
/** * 后羿 */ public class HouYiHero implements Hero { @Override public void haveHero() { System.out.println("勇士,恭喜你获得了英雄-后羿"); } }

 

我们知道英雄还有皮肤,所以我们定义第二个抽象角色,即皮肤的顶层接口

/** * 皮肤 */ public interface Skin { void haveSkin(); }

 

接着定义皮肤接口的实现类

/** * 妲己皮肤 */ public class DaJiSkin implements Skin{ @Override public void haveSkin() { System.out.println("恭喜你获得了皮肤-热情桑巴"); } }
/** * 程咬金皮肤 */ public class ChengYaoJinSkin implements Skin { @Override public void haveSkin() { System.out.println("恭喜你获得了皮肤-爱与正义"); } }
/** * 后羿皮肤 */ public class HouYiSkin implements Skin{ @Override public void haveSkin() { System.out.println("恭喜你获得了皮肤-黄金射手座"); } }

 

根据上面的概念,我们定义完了2个抽象角色,那么还需定义一个抽象工厂。可能你会问为什么要定义一个抽象工厂,因为上面的概念也说到了定义抽象工厂的目的就是为了派生具体的工厂类(也就是让子类去实现)。这个抽象工厂类加上abstract 关键字后,又该如何去写内部的逻辑,我想这一块才是最需要思考和解决的问题。

/** * 商品工厂(顶层多态接口 ) */ public interface MarketFactory { }
/** * 英雄抽象工厂 */ public abstract class HeroAbStractFactory implements MarketFactory { public abstract Hero getHero(String heroType); }
/** * 皮肤抽象工厂 */ public abstract class SkinAbStractFactory implements MarketFactory { public abstract Skin getSkin(String skinType); }

 

定义完抽象工厂,我们实现两个工厂

/** * 英雄工厂 */ public class HeroFactory extends HeroAbStractFactory { @Override public Hero getHero(String heroType) { if("HouYi".equals(heroType)){ return new HouYiHero(); }else if("DaJi".equals(heroType)){ return new DaJiHero(); }else if("ChengYaoJin".equals(heroType)){ return new ChengYaoJinHero(); } return null; } }
/** * 皮肤工厂 */ public class SkinFactory extends SkinAbStractFactory { @Override public Skin getSkin(String skinType) { if("HouYi".equals(skinType)){ return new HouYiSkin(); }else if("DaJi".equals(skinType)){ return new DaJiSkin(); }else if("ChengYaoJin".equals(skinType)){ return new ChengYaoJinSkin(); } return null; } }

 

那么,我们已经定义完具体的实例工厂,一个是英雄工厂,一个是皮肤工厂,现在可以定义一个统一管理类管理这两个工厂

/** * 工厂(商城) */ public class FactoryProduct { public static MarketFactory getFactoryByType(String factoryType){ if("HeroFactory".equals(factoryType)){ return new HeroFactory(); }else if("SkinFactory".equals(factoryType)){ return new SkinFactory(); } return null; } }

 

最后我们开始测试

/** * 工厂测试 */ public class TestFactory { public static void main(String[] args) { HeroFactory heroFactory = (HeroFactory) FactoryProduct.getFactoryByType("HeroFactory"); Hero hero = heroFactory.getHero("ChengYaoJin"); hero.haveHero(); SkinFactory skinFactory = (SkinFactory) FactoryProduct.getFactoryByType("SkinFactory"); Skin skin = skinFactory.getSkin("ChengYaoJin"); skin.haveSkin(); } }


__EOF__

本文作者丁可乐
本文链接https://www.cnblogs.com/dwlovelife/p/13270146.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   丁可乐  阅读(572)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示