{C#}设计模式辨析.工厂方法
2021-08-02 本文已影响0人
码农猫爸
辨析的背景
-
学习了很多高手的设计模式,却无法应用到自己的代码
-
设计模式间存在相似性,不能明显区分落地场景
-
应用设计模式有成本,需平衡代码的可读性和弹性
-
扩展阅读
-
设计模式全家桶
-
单产品(变形1)
- 最简代码,个人代码中常见
- 无法应对同类产品的增加,产品不变时OK
using static System.Console;
namespace SingleProduct
{
public class Pencil
{
public void Make() => WriteLine("One pencil is made.");
}
public class Client
{
private Pencil pencil = new Pencil();
public void Execute() => pencil.Make();
}
class Demo
{
// 单一产品时无需接口,最简代码也可运行
static void Main(string[] args)
{
var client = new Client();
client.Execute();
}
}
}
同类多产品(变形2)
- 接口实现同类产品互换,可应对产品的增加
- 不能选择某个产品生产,产品不变且全部生产时OK
using static System.Console;
namespace AllProducts
{
interface IStationery { void Make(); }
public class Pencil : IStationery
{
public void Make() => WriteLine("One pencil is made.");
}
public class Knife : IStationery
{
public void Make() => WriteLine("One Knife is made.");
}
public class Client
{
// 多个类似产品,接口可保证互换性
private IStationery stationery;
// 生产所有产品
public void Execute()
{
stationery = new Pencil();
stationery.Make();
stationery = new Knife();
stationery.Make();
}
}
class Demo
{
static void Main(string[] args)
{
var client = new Client();
client.Execute();
}
}
}
简单工厂(变形3)
- 同类多产品基础上,可选产品生产
- 违背单一职责(SRP)原则,直接NG
- 优势:调用时省略了生成细节
- 要点:引入分支判断
using System;
using static System.Console;
namespace SimpleFactory
{
// 省略文具接口和其子类,见同类多产品
public class Client
{
public void Execute(string name)
{
// 多个类似产品,接口可保证互换性
IStationery stationery;
// 按品名生产
switch (name)
{
case "pencil":
stationery = new Pencil();
break;
case "knife":
stationery = new Knife();
break;
default:
throw new Exception("无此产品");
}
stationery.Make();
}
}
class Demo
{
static void Main(string[] args)
{
// 如需生产橡皮,应
// - 增加IStationery的子类Rubber,不影响旧代码
// - 增加Client中分支语句,影响旧代码(不符合单一职责,NG)
// - 修改本类中品名,影响旧代码(必须)
var client = new Client();
client.Execute("pencil");
}
}
}
工厂方法(变形4)
- 简单工厂基础上,遵守单一职责(SRP)原则
- 要点:具体工厂中通过重写接口方法(模式得名)绑定同类具体产品,不接受产品传参
using static System.Console;
namespace FactoryMethod
{
// 省略文具接口和其子类,见同类多产品
public interface IFactory { IStationery CreateStationery(); }
public class PencilFactory : IFactory
{
// 工厂与产品已绑定,调用时仅关注工厂即可
public IStationery CreateStationery() => new Pencil();
}
public class KnifeFactory : IFactory
{
public IStationery CreateStationery() => new Knife();
}
public class Client
{
// 多个类似工厂,接口可保证互换性
private readonly IFactory factory;
public Client(IFactory factory)
{
this.factory = factory;
}
public void Execute()
{
var stationery = factory.CreateStationery();
stationery.Make();
}
}
class DesignPattern
{
static void Main(string[] args)
{
// 如需生产橡皮,应
// - 增加IStationery的子类Rubber,不影响旧代码
// - 增加IFactory的子类RubberFactory,不影响旧代码
// - 修改本类中工厂,影响旧代码(必须)
var factory = new PencilFactory();
var client = new Client(factory);
client.Execute();
}
}
}
奇怪的工厂(变形5)
- 工厂方法基础上,合并了工厂子类,违背了不关心生成细节的初心
using static System.Console;
namespace OddFactory
{
// 省略接口IStationery, 子类Pencil & Knife
public class Factory
{
// 工厂未绑定产品
private readonly IStationery stationery;
public Factory(IStationery stationery)
{
this.stationery = stationery;
}
public void Make() => stationery.Make();
}
public class Client
{
private readonly Factory factory;
public Client(Factory factory)
{
this.factory = factory;
}
public void Execute() => factory.Make();
}
class Demo
{
static void Main(string[] args)
{
// - 违背了工厂方法的初心,不应关注生成细节
// - 增加了代码层次和理解难度
var pencil = new Pencil();
var factory = new Factory(pencil);
var client = new Client(factory);
client.Execute();
}
}
}