工厂模式
简单工厂
- 根据工厂类中方法传入的参数返回所需的对象。
- 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象逻辑不关心
- 优点:只需要传入一个正确的参数,就可以获取你所需要的对象而无需知道其创建的细节
- 缺点:工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则
coding:
public interface IChat { void chatting(String seqNo); } public class QQ implements IChat { @Override public void chatting(String seqNo) { System.out.println("使用QQ进行聊天 -- " + seqNo); } } public class WeiXin implements IChat { @Override public void chatting(String seqNo) { System.out.println("使用微信进行聊天 -- " + seqNo); } } public class ChatFactory1 { public IChat createChat(String tools){ if("QQ".equals(tools)){ return new QQ(); }else if("WeiXin".equals(tools)) { return new WeiXin(); }else{ return null; } } } public class FactoryTest { public static void main(String[] args) { // 1、使用单方法工厂模式进行测试 ChatFactory1 chatFactory1 = new ChatFactory1(); String seqNo = "1"; IChat weixin1 = chatFactory1.createChat("WeiXin"); weixin1.chatting(seqNo); IChat qq1 = chatFactory1.createChat("QQ"); qq1.chatting(seqNo); IChat momo = chatFactory1.createChat("MoMo"); if(momo == null){ System.out.println("创建陌陌聊天工具实例失败"); }else{ momo.chatting(seqNo); } } }
UML
FactoryTest只创建ChatFactory工厂,QQ和WeiXin由ChatFactory工厂创建。缺点很明显,创建MoMo,就需要修改ChatFactory类,这不符合开闭原则。
反射方式改造
public class ChatFactory { public IChat createChat(Class c){ IChat iChat = null; try { iChat =(IChat) Class.forName(c.getName()).getConstructor().newInstance(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } return iChat; } }
工厂方法
- 定义一个工厂接口(或抽象类),实现这个工厂接口的工厂类去决定实例化哪个类,一个工厂类只实例化一个类
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 一个类通过其子类类指定创建哪个对象
- 优点:加入新产品符合开闭原则,提高可扩展性
- 缺点:类的个数容易过来,增加复杂度,增加了系统的抽象性和理解难度
coding:
public interface IChat { void chatting(String seqNo); } /** 三个实例对象 */ public class WeiXinChat implements IChat { @Override public void chatting(String seqNo) { System.out.println("使用微信进行聊天 -- " + seqNo); } } public class QQChat implements IChat { @Override public void chatting(String seqNo) { System.out.println("使用QQ进行聊天 -- " + seqNo); } } public class QQChat implements IChat { @Override public void chatting(String seqNo) { System.out.println("使用QQ进行聊天 -- " + seqNo); } } /** * 只制定规范契约,并不决定产生哪一种类的实例,产生哪一种实例完全交由子类实现 */ public abstract class ChatFactory { public abstract IChat getChat(); } public class WeiXinChatFactory extends ChatFactory{ @Override public IChat getChat() { return new QQChat(); } } public class QQChatFactory extends ChatFactory{ @Override public IChat getChat() { return new QQChat(); } } public class MoMoChatFactory extends ChatFactory{ @Override public IChat getChat() { return new MoMoChat(); } } public class Test { public static void main(String[] args) { ChatFactory weiXinChatFactory = new WeiXinChatFactory(); ChatFactory qqChatFactory = new QQChatFactory(); ChatFactory moMoChatFactory = new MoMoChatFactory(); IChat chat = moMoChatFactory.getChat(); chat.chatting("11"); } }
UML
可以看到三个实例工厂对应生产三个类的实例,Test测试类中要使用哪个实例,直接找对象的工厂实例get即可。
抽象工厂
- 一个抽象工厂接口,包含一系列创建的接口方法,这些方法的返回是一个接口,意味着一个接口方法可以生产实现该接口的所有类对象。
- 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,无需指定他们具体的类
- 使用场景:
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关产品对象(属于同一产品族,产品族概念后面有解释)一起使用创建对象需要大量重复的代码
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现
- 优点
- 具体产品在应用层代码隔离,无需关心创建细节
- 将一个系列的产品族统一到一起创建
- 缺点
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
- 增加了系统的抽象性和理解难度
coding
- 电脑抽象工厂接口 == 只提供电脑组件的组装,具体组装成什么样型号的电脑,再由具体工厂类决定
public interface IComputerFactory { IProduceKeyBord createKeyBord(); IProduceMouse createMouse(); }
- 键盘接口 -- 生产键盘
public interface IProduceKeyBord { /** * 约定键盘生产的规格数据 * @param name 名称 * @param color 颜色 */ void produceKeyboard(String name, String color); }
- 鼠标接口 -- 生产鼠标
public interface IProduceMouse { /** * 约定鼠标生产的规格数据 * @param name 名称 * @param type 类型 */ void produceMouse(String name,String type); }
- 雷柏(Rapoo)鼠标键盘生产商
public class LeiBoMouse implements IProduceMouse { @Override public void produceMouse(String name, String type) { System.out.println("雷柏鼠标 -- "+name+","+type); } } public class LeiBoKeyboard implements IProduceKeyBord { @Override public void produceKeyboard(String name, String color) { System.out.println("雷柏键盘 -- "+name+","+color); } }
- 罗技(G)鼠标键盘生产商
public class LuoJiKeyboard implements IProduceKeyBord { @Override public void produceKeyboard(String name, String color) { System.out.println("罗技键盘 -- "+name+","+color); } } public class LuoJiMouse implements IProduceMouse { @Override public void produceMouse(String name, String type) { System.out.println("罗技鼠标 -- "+name+","+type); } }
- 联想电脑生产商 == 电脑型号01【固定键盘和鼠标生产商】
public class LianXiang01Factory implements IComputerFactory { @Override public IProduceKeyBord createKeyBord() { // 使用雷柏的键盘 return new LeiBoKeyboard(); } @Override public IProduceMouse createMouse() { // 使用雷柏的鼠标 return new LeiBoMouse(); } }
- 联想电脑生产商 == 电脑型号:02【固定键盘和鼠标生产商】
public class LianXiang02Factory implements IComputerFactory { @Override public IProduceKeyBord createKeyBord() { // 使用雷柏的键盘 return new LeiBoKeyboard(); } @Override public IProduceMouse createMouse() { // 使用罗技的鼠标 return new LuoJiMouse(); } }
抽象工厂测试 == 具体工厂类实现不同电脑组件的生产
public class AFactoryTest { public static void main(String[] args) { // 用户需要购买联想的电脑,但要求键盘和鼠标都是雷柏的,于是便找到了对应的01电脑组装工厂进行生产 LianXiang01Factory lianXiang01Factory = new LianXiang01Factory(); IProduceKeyBord keyboard1 = lianXiang01Factory.createKeyBord(); keyboard1.produceKeyboard("M550", "黑色"); IProduceMouse Mouse1 = lianXiang01Factory.createMouse(); Mouse1.produceMouse("M590", "有线"); System.out.println("=======================分割线,注意区别"); // 用户需要购买联想的电脑,但要求键盘是雷柏的,鼠标是罗技的,于是便找到了对应的02电脑组装工厂进行生产 LianXiang02Factory lianXiang02Factory = new LianXiang02Factory(); IProduceKeyBord keyboard2 = lianXiang02Factory.createKeyBord(); keyboard2.produceKeyboard("M550", "黑色"); IProduceMouse Mouse2 = lianXiang02Factory.createMouse(); Mouse2.produceMouse("M590", "无线"); /** * 好处:横向扩展很容易,如果我需要再增加一个电脑型号的生产线,比如HP【惠普】,只需要在创建一个对应的工厂实现抽象工厂即可 * 坏处:纵向扩展很麻烦,如果我需要增加显示器的生产接口,那么改动的地方就太多了。 */ } }