[TOC]
工厂模式(持续更新)
我们这里以手机销售作为应用场景,后续设计模式也尽量贴近生活(使用学校例子(●’◡’●))
(感觉这里有点设计问题,写到后面感觉人麻了,自己理解不深以及应用场景想的不太好)
简单工厂模式
初代设计
首先设计一个手机商店
package factoryMod;
public class PhoneStore { public Phone sellPhone(String type){ Phone phone; switch (type) { case "xiaomi" -> phone = new xiaomiPhone(); case "oppo" -> phone = new oppoPhone(); case "huawei" -> phone = new huaweiPhone(); default -> { System.out.println("没有该手机"); return null; } } phone.prepare(); phone.okSell(); phone.pack(); return phone; } }
|
然后设计一个手机抽象类,让不同品牌的手机继承该类(后续会讨论为什么要在手机这里设置这些方法而不是在商店里面,明明商店才是卖手机的啊)(当然了,个人想法,只是想法罢了)
public abstract class Phone { protected String name;
public void prepare(){ System.out.printf("准备%s手机的盒子、充电线等\n",name); }
public void okSell(){ System.out.println("完成付款"); }
public void pack(){ System.out.printf("%s被你打包带走\n",name); } }
|
然后具体的品牌的手机继承该类
public class xiaomiPhone extends Phone{
public xiaomiPhone(){ this.name="小米"; } }
----------------------------------------
public class oppoPhone extends Phone{
public oppoPhone(){ this.name="OPPO"; }
}
---------------------------------------- public class huaweiPhone extends Phone{
public huaweiPhone(){ this.name="华为"; } }
|
写完之后不难发现,要是有新品牌手机出现或者说现有品牌手机不再供应,本该是增删对应品牌的手机就行,但是手机店的销售函数也要进行更改,显然是不合理的。
简单工厂使用
设计一个工厂,跟生活一样,手机有生产的工厂,而不是交给手机店判断种类以及生产,它职责只是负责拿到货然后售卖。
public class PhoneFactory { public Phone createPhone(String type) { Phone phone = null; switch (type) { case "xiaomi" -> phone = new xiaomiPhone(); case "oppo" -> phone = new oppoPhone(); case "huawei" -> phone = new huaweiPhone(); default -> System.out.println("没有该手机"); } return phone; } }
|
相应的手机店
public class PhoneStore {
public Phone sellPhone(String type) { Phone phone = new PhoneFactory().createPhone(type); phone.talkPrice(); phone.okSell(); phone.pack(); return phone; } }
------------------------------- 或者提前与某家工厂合作 public class PhoneStore {
private PhoneFactory phoneFactory; public PhoneStore(PhoneFactory phoneFactory){ this.phoneFactory=phoneFactory; } public Phone sellPhone(String type) { Phone phone = new PhoneFactory().createPhone(type); phone.talkPrice(); phone.okSell(); phone.pack(); return phone; } }
|
这样的话,能够将职责进行转移。比较手机的创建过程与手机店无关。(单一责任原则)
工厂方法模式
使用简单工厂确实将创建手机的过程转移到了工厂,让商店只负责卖手机就行,但是还是有问题,当我们添加新品牌手机时,还是会改动手机工厂中的case语句,还是违背了封闭-开放原则(不改动,支持扩展)
因此将采用工厂方法模式。
定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
首先设计一个手机工厂的接口。
public interface PhoneFactory { public Phone createPhone(); }
|
然后其他手机实现这个接口(基本一致,只展示xiaomi工厂)
public class XiaomiFactory implements PhoneFactory {
@Override public Phone createPhone() { return new xiaomiPhone(); } }
|
这样的话,加入新的或者删除不同品牌的手机就不会去改动case判断语句了。
通过手机店去选择卖什么手机然后进行相应的实例化即可。但是代价就是加入新的品牌时,不仅要添加一个实体类,还要写对应的实体从创建工厂。相当于一次性要写两个类了。并且判断转移成了,商店得知道是哪个工厂创建的这个手机。
手机店的代码。
public class PhoneStore { public Phone sellPhone() { PhoneFactory phoneFactory=new HuaweiFactory(); Phone phone = phoneFactory.createPhone(); phone.prepare(); phone.okSell(); phone.pack(); return phone; } }
|
抽象工厂模式
定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
我们刚刚的手机店生意很好,所以打算搞连锁店,在北上广深都搞分店然后突击海外市场(doge)
这里也可以采用具体的手机品牌,然后就有了国内手机工厂的接口和国外手机工厂的接口,再去创建具体的品牌,但是这里只是讲解模式并不涉及太复杂的场景。
所以首先定义一个商店的工厂
public interface Factory { public Phone createPhone(); public Ipad createIpad(); }
|
然后商店进行实现
public class CNFactory implements Factory{
@Override public Phone createPhone() { return new CNPhone(); }
@Override public Ipad createIpad() { return new CNIpad(); } }
|
然后是平板和手机的接口,让具体的手机进行实现
public interface Ipad {
public void prepare();
public void okSell();
public void pack(); }
|
public class CNIpad implements Ipad{ @Override public void prepare() {
}
@Override public void okSell() {
}
@Override public void pack() {
} }
|
然后当我们使用国内或者国外的产品时,只需要更改实例化对象即可
public class Main { public static void main(String[] args) {
Factory factory=new ForeignFactory(); Ipad ipad = factory.createIpad(); ipad.pack(); } }
|
但是我们会发现,当我们添加一个电脑产品时,必须加入PC接口,CN-PC类,ForeignPC类,那是相当麻烦的。
并且这里的客户端必须得知道国内工厂和国外工厂的创建实例方法。
使用反射优化抽象工厂(待更新)
总结
在码代码过程中,也会发现,其实我们平时要是对多态使用较多的话,其实已经是在使用工厂模式了,只是没有将它抽象成一个词汇而已。并且选择模式时需要根据实际情况去选择相性较好的模式,不然会出现设计过度反倒更加复杂的情况,导致得不偿失。
不要有把新锤子就看什么都是钉子(但是还是得慢慢捶过才知道哪些该捶啊)还是得不断挨打才能成长。
在简单的场景使用简单工厂甚至于使用面向过程编程会更加简单快捷,所以希望能够慢慢磨练成长吧,从不知道设计模式,到知道并且使用,到使用但是没有刻意去想的境界。
所以啦,不要刻意去记下什么场景用什么模式,而是清楚这个模式能够解决什么问题,这样还能多个模式相结合。