简单工厂,工厂方法,抽象工厂的进阶之路
文章目录
前言
工厂方法和抽象工厂都是创建型设计模式,工厂模式在父类中提供一个创建对象的接口,允许子类决定实例化对象的类型。
抽象工厂能创建一系列相关的对象,而无需指定其具体类。但简单工厂模式不是 23 种里的一种,简而言之,就是有一个专门生产某个产品的类。
一、抛出问题
1.我们为什么要使用简单工厂?
2.简单工厂遇到了什么困难要让我们使用工厂模式?
3.工厂模式遇到的困境,抽象工厂是如何解决的?
4.抽象工厂的缺点
这四个问题是我们在使用这三种之前所要思考清楚的,什么时候该用,如何改进,如何在改进的基础上进一步改进。
二、回答问题
1.我们为什么要使用简单工厂?
简单工厂的优点和使用场景:
-
工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
-
想要隔离具体实现,让客户端只通过接口操作。想要把创建对象的职责集中管理和控制。
简单工厂的出现,让客户端可以更好的面向接口编程,降低了耦合性。但是每次添加子类的时候,则是非常之麻烦,十分不方便。
2.简单工厂遇到了什么困难要让我们使用工厂模式?
A.简单工厂的解决方法
首先,我们先设想一下:
你有两部手机需要生产,而你只有一个工厂,客户发什么订单,你就按订单生产。
using System;
namespace ConsoleApplication4
{
public class SimplePhoneFactory
{
public Phone GetFactory(string a)
{
if (a=="苹果")
{
return new ApplePhone();
}
return new XiaoMiPhone();
}
}
public interface Phone
{
void call();
void look();
}
public class ApplePhone:Phone
{
public void call()
{
Console.WriteLine("苹果手机给你打电话了");
}
public void look()
{
Console.WriteLine("苹果手机要给你视频通话");
}
}
public class XiaoMiPhone:Phone
{
public void call()
{
Console.WriteLine("小米手机给你打电话了");
}
public void look()
{
Console.WriteLine("小米手机要给你视频通话");
}
}
}
客户端调用代码:
//客户端调用
SimplePhoneFactory phoneFactory=new SimplePhoneFactory();
Phone aPhone=phoneFactory.GetFactory("苹果");
aPhone.call();
aPhone.look();
在这里,客户端调用的时候,完全不用知道工厂类的内部结构和实现逻辑,也能制造一个有效的product。
这个就是简单工厂的优点,那就是客户端无需了解内部类。
让我们想一下, 如果我们需要更多的手机,那就意味着需要在SimplePhoneFactory的GetFactory里重复添加更多的return 方法用来获得对象。而且这里只提供了两个手机品牌,if-else完全就可以解决,但是就像之前说的,如果提供更多手机,庞大的if-else会让维护者感到十分头痛,新手程序员们(当然也包括我)很难做到一开始就使用设计模式或者是字典来代替if-else。
那么我们现在应该做的事情,就是尽可能减少多个商品类对于工厂类的影响。
B.工厂模式的解决方法:
现在我们扩大了生产线,在之前的基础上加盖了XiaoMi工厂和Apple工厂并且拥有了两家家全新的工厂——HUAWEI工厂和OnePlus工厂。那么我们需要如何做呢?
- 创建总厂
- 创建具体厂
- 创建商品接口
- 创建商品类
using System;
namespace ConsoleApplication4
{
public interface IFactory
{
IPhone GetPhone();
}
public class ApplePhoneFactory : IFactory
{
public IPhone GetPhone()
{
return new ApplePhone();
}
}
public class XiaoMiPhoneFactory : IFactory
{
public IPhone GetPhone()
{
return new XiaoMiPhone();
}
}
public interface IPhone
{
void call();
void look();
}
public class ApplePhone:IPhone
{
public void call()
{
Console.WriteLine("苹果手机给你打电话了");
}
public void look()
{
Console.WriteLine("苹果手机要给你视频通话");
}
}
public class XiaoMiPhone:IPhone
{
public void call()
{
Console.WriteLine("小米手机给你打电话了");
}
public void look()
{
Console.WriteLine("小米手机要给你视频通话");
}
}
}
客户端调用:
IFactory factory=new ApplePhoneFactory();
IPhone phone = factory.GetPhone();
phone.call();
phone.look();
在这里我们清晰可见,具体生产哪个商品,无需在工厂类中提供各种可能的返回对象,只需要在客户端中调用就行了。
3.工厂模式遇到的困境,抽象工厂是如何解决的?
为了回答这个问题,我们首先要思考一下,工厂模式遇到了什么困难,以至于让我们需要将工厂模式升级为抽象工厂模式呢?
很简单,就是你没那么多时间精力去创建并且管理工厂的时候,你会渴望有个足够抽象的工厂,能将产品类集中起来。而不是像工厂模式那样,创建比较具体的工厂比如:桌子——桌子工厂。
using System;
namespace ConsoleApplication4
{
public interface abstractFactory
{
Pad createPad();
Phone createPhone();
}
public interface Pad
{
void PlayPad();
}
public interface Phone
{
void PlayPhone();
}
public class Apple : abstractFactory
{
public Pad createPad()
{
return new ApplePad();
}
public Phone createPhone()
{
return new ApplePhone();
}
}
public class ApplePad : Pad
{
public void PlayPad()
{
Console.WriteLine("hello ipad");
}
}
public class ApplePhone : Phone
{
public void PlayPhone()
{
Console.WriteLine("hello iphone");
}
}
}
//客户端
namespace ConsoleApplication4
{
internal class Program
{
public static void Main(string[] args)
{
abstractFactory _abstract=new Apple();
Pad pad = _abstract.createPad();
pad.PlayPad();
}
}
}
每个产品虽然不尽相同,但是它们都有一部分相同的特质,完成的任务也可能有相同。所以将这些“相同的特质”抽象出来,就完成了抽象工厂模式的第一步。
实例 -> 类 -> 类工厂
实例 -> 类 -> 类工厂 -> 抽象工厂
抽象工厂模式和工厂模式的区别? - 徐大肉的回答 - 知乎
https://www.zhihu.com/question/20367734/answer/44379717
4.抽象工厂的缺点
难以支持新种类的产品。因为抽象工厂接口确定了可以被创建的产品集合,所以难以扩展抽象工厂以生产新种类的产品。
简单的说,就是扩展性差。