1、工厂方法模式解决的问题

现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路.

前提:抽象变化较慢,实现变化较快(不稳定)

整个抽象的游戏设施建造系统相对变化较慢,本例中只有一个Build的创建方法,而Build内部的方法实现,该实现依赖与各种具体的实现,而这些实现变化的非常频繁,现在虽然只有现代风格和古典风格的房屋和道路的构建,而将来可能会卡通风格、另类风格等各种各样的对象加入到Build方法中来渲染游戏的背景.

在不考虑第三方容器组件(如Unity)和设计模式的情况下,为了快速完成这个任务,我们通常会用以下这种方式编码,代码如下:

    #region 抽象A
/// <summary>
/// 抽象的游戏设施建造系统
/// </summary>
public class BuildSystem
{
/// <summary>
/// Build方法的逻辑变化较慢(只需要创建2种风格的房屋和道路,总共8个对象),但是风格变化较快,由于需求变化,可能需要创建诸如卡通风格、另类风格等的房屋和道路
/// </summary>
public void Builld()
{
ModernHouse modernHouseA = new ModernHouse();
ModernHouse modernHouseB = new ModernHouse();
ModernRoad modernRoadA = new ModernRoad();
ModernRoad modernRoadB = new ModernRoad();
ClassicalHouse classicalBuildA = new ClassicalHouse();
ClassicalHouse classicalBuildB = new ClassicalHouse();
ClassicalRoad classicalRoadA = new ClassicalRoad();
ClassicalRoad classicalRoadB = new ClassicalRoad();
//下面是具体的对象实例操作,如现代化房屋虽然有两个实例,但是可能两个可能高矮、外形不同等
}
}
#endregion #region 实现细节b
/// <summary>
/// 现代风格的房屋
/// </summary>
public class ModernHouse { } /// <summary>
/// 现代风格的道路
/// </summary>
public class ModernRoad { } /// <summary>
/// 古典风格的房屋
/// </summary>
public class ClassicalHouse { } /// <summary>
/// 古典风格的道路
/// </summary>
public class ClassicalRoad { }
#endregion

客户端调用代码如下:

    class Program
{
static void Main(string[] args)
{
BuildSystem buildSystem = new BuildSystem();
buildSystem.Builld();
}
}

从oop的角度分析上面的代码:

1、Build方法的主逻辑稳定(变化较慢),构建两种风格的房屋和道路,目前只需要构建8个对象,后续可扩展.

2、虽然上面的代码完成1中的要求,但是无法应对后续的扩展,假设新增加了一个需求,Build方法需要能切换风格,完成卡通和另类风格的房屋和道路的构建,显然上面的代码无法完成这个需求.(当然你可以在BuildSystem中新添一种新的Build方法来满足需求,但是这种方式的代码的重用性差)

3、代码的大致结构如下图:

代码虽然拥有大致的主逻辑,但是和各个子模块糅合在一起,代码复用性差,Build方法(抽象)依赖于其下面的具体实现,如下图:

所以我们需要对代码进行重构.

    /// <summary>
/// 抽象的游戏建造系统
/// </summary>
public class BuildSystem
{
/// <summary>
/// 具体的构建方法,Build方法的逻辑变化较慢(只需要创建2种风格的房屋和道路,总共8个对象),但是风格变化较快,由于需求变化,可能需要创建诸如卡通风格、另类风格等的房屋和道路
/// </summary>
public void Build(HouseFactory houseFactoryOne, HouseFactory houseFactoryTwo,RoadFactory roadFactoryOne, RoadFactory roadFactoryTwo)
{
House HFirstStyleOne = houseFactoryOne.CreateHouse();
Console.WriteLine(HFirstStyleOne.ShowHouseStyle());
House HFirstStyleTwo = houseFactoryOne.CreateHouse();
Console.WriteLine(HFirstStyleTwo.ShowHouseStyle());
Road RFirstStyleOne = roadFactoryOne.CreateRoad();
Console.WriteLine(RFirstStyleOne.ShowRoadStyle());
Road RFirstStyleTwo = roadFactoryOne.CreateRoad();
Console.WriteLine(RFirstStyleTwo.ShowRoadStyle());
House HSecondStyleOne = houseFactoryTwo.CreateHouse();
Console.WriteLine(HSecondStyleOne.ShowHouseStyle());
House HSecondStyleTwo = houseFactoryTwo.CreateHouse();
Console.WriteLine(HSecondStyleTwo.ShowHouseStyle());
Road RSecondStyleOne = roadFactoryTwo.CreateRoad();
Console.WriteLine(RSecondStyleOne.ShowRoadStyle());
Road RSecondTwo= roadFactoryTwo.CreateRoad();
Console.WriteLine(RSecondTwo.ShowRoadStyle());
}
} #region 抽象工厂方法
/// <summary>
/// 抽象的House工厂方法
/// </summary>
public abstract class HouseFactory
{
public abstract House CreateHouse();
} /// <summary>
/// 抽象的Road工厂方法
/// </summary>
public abstract class RoadFactory
{
public abstract Road CreateRoad();
} #endregion #region 工厂方法
public class ModernHouseFactory : HouseFactory
{
public override House CreateHouse()
{
return new ModernHouse();
}
} public class ModerRoadFactory : RoadFactory
{
public override Road CreateRoad()
{
return new ModernRoad();
}
} public class ClassicalHouseFactory : HouseFactory
{
public override House CreateHouse()
{
return new ClassicalHouse();
}
} public class ClassicalRoadFactory : RoadFactory
{
public override Road CreateRoad()
{
return new ClassicalRoad();
}
} public class CartoonHouseFactory : HouseFactory
{
public override House CreateHouse()
{
return new CartoonHouse();
}
} public class CartoonRoadFactory : RoadFactory
{
public override Road CreateRoad()
{
return new CartoonRoad();
}
} public class AlternativeHouseFactory : HouseFactory
{
public override House CreateHouse()
{
return new AlternativeHouse();
}
} public class AlternativeRoadFactory : RoadFactory
{
public override Road CreateRoad()
{
return new AlternativeRoad();
}
}
#endregion #region 抽象
public abstract class House
{
public abstract string ShowHouseStyle();
} public abstract class Road
{
public abstract string ShowRoadStyle();
}
#endregion #region 具体的实现
public class ModernHouse : House
{
public override string ShowHouseStyle()
{
return "Modern现代化风格房屋";
}
} public class ModernRoad : Road
{
public override string ShowRoadStyle()
{
return "Modern现代化风格道路";
}
} public class ClassicalHouse : House
{
public override string ShowHouseStyle()
{
return "Classical古典化风格房屋";
}
} public class ClassicalRoad : Road
{
public override string ShowRoadStyle()
{
return "Classical古典化风格道路";
}
} public class CartoonHouse : House
{
public override string ShowHouseStyle()
{
return "Cartoon卡通化风格房屋";
}
} public class CartoonRoad : Road
{
public override string ShowRoadStyle()
{
return "Cartoon卡通化风格道路";
}
} public class AlternativeHouse : House
{
public override string ShowHouseStyle()
{
return "Alternative另类化风格房屋";
}
} public class AlternativeRoad : Road
{
public override string ShowRoadStyle()
{
return "Alternative另类化风格道路";
}
}
#endregion

客户端调用代码如下:

    /// <summary>
/// FactoryMethod工厂方法-创建型模式
/// </summary>
class Program
{
static void Main(string[] args)
{
BuildSystem buildSystem = new BuildSystem();
buildSystem.Build(new CartoonHouseFactory(), new AlternativeHouseFactory(), new CartoonRoadFactory(),new AlternativeRoadFactory());
Console.ReadKey();
}
}

ok,重构后的代码很好的完成的了需求,而且扩展性更高,这就是FactoryMethod工厂模式,通过工厂模式,完成对主逻辑的整理,让主逻辑不在依赖具体的实现细节,而是依赖于抽象工厂.,通过传入的具体类型的工厂类来完成具体类型的创建,如果后续需要增加具体类型实例的实例,则只需要调用Create方法即可,完成依赖倒置.

重构后的代码如下图:

中间的实折现代表Build方法,主逻辑稳定,圈圈代表抽象工厂类,通过抽象工厂类完成主逻辑和实现的解耦.

虽然工厂模式能很好的解决这一类问题,但是如果具体的实现细节过多,比如在增加N种风格的房屋和道路,这个时候就会存在工厂泛滥的问题?

解决方案如下:

1、使用第三方依赖注入工具,如Unity等  参考控制反转和依赖注入模式

2、使用原型模式,原型模式能很好的解决工厂泛滥的问题.关于原型模式,请参考原型模式(创建型模式)

关于抽象工厂模式和工厂模式的区别:

工厂模式只能解决单个对象的需求变化,实际上面的代码还能进一步进行抽象,对工厂类进行抽象,将现代化的道路和房屋抽象到一起,构成一个现代化风格系列对象创建工厂,这个时候就是工厂模式的升级版-抽象工厂,抽象工厂模式解决系列对象的对象变化.

FactoryMethod工厂方法模式(创建型模式)的更多相关文章

  1. Prototype原型模式(创建型模式)

    1.原型模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只有一 ...

  2. 工厂方法模式——创建型模式02

    1. 简单工厂模式     在介绍工厂方法模式之前,先介绍一下简单工厂模式.虽然简单工厂模式不属于GoF 23种设计模式,但通常将它作为学习其他工厂模式的入门,并且在实际开发中使用的也较为频繁. (1 ...

  3. 设计模式(三): FACTORY工厂模式 -- 创建型模式

    1.定义 定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类. 2.适用场景 1.第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体 ...

  4. 设计模式(五):PROTOTYPE原型模式 -- 创建型模式

    1.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.适用场景 原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对 ...

  5. 设计模式(二): BUILDER生成器模式 -- 创建型模式

    1.定义 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 2.适用场景 1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式 ...

  6. C#设计模式--工厂模式(创建型模式)

    一.简单工厂模式(UML类图): 核心类代码: public class Calc { public double NumberA { get; set; } public double Number ...

  7. 工厂模式/factory模式/创建型模式

    工厂模式 普通工厂模式 原本需要new出来的对象,通过一个类的方法去搞定,Factory.build(parameter),类似这种. public interface Sender { public ...

  8. 设计模式(四):SIMPLE FACTORY简单工厂模式 -- 创建型模式

    1.定义 简单工厂模式又称静态工厂方法模式.重命名上就可以看出这个模式一定很简单.它存在的目的很简单:定义一个用于创建对象的接口. 2.适用场景 如果一个客户要一款宝马车,一般的做法是客户去创建一款宝 ...

  9. 设计模式(一): abstract factory抽象工厂模式 -- 创建型模式

    1.定义 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 2.适用场景 1.一个系统要独立于它的产品创建.组合和表示. 2.一个系统要由多个产品系列中的一个来配置. 3.当你要 ...

随机推荐

  1. c# 得到list符合某条件的索引值,排序

    请教,在List集合中怎么得到元素的索引值,参考:http://www.myexception.cn/c-sharp/385022.html 这个可以用来读取窗口的多个textbox控件中内容: -- ...

  2. vue的饿了么写作感受

    1.在重复使用的组件中,要把重复使用组件的需要在数据的请求的地方设置为在富组件中,通过props船只到子组件,这样在重复调用次组件的时候既可以很好的避免组件的值的冲突 2.getData的使用,把所有 ...

  3. vue中的路由独享守卫的理解

    1.vue中路由独享守卫意思就是对这个路由有一个单独的守卫,因为他的守卫方式于其他的凡是不太同 独享守卫于前置守卫使用方法大致是一样的 在路由配置的时候进行配置, { path:'/login', c ...

  4. js动态删除某一行,内容超出单元格后超出的部分用省略号代替

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <s ...

  5. java通过sftp对linux服务器文件夹进行操作

    本文主要讲sftp对linux服务器的文件和文件夹进行操作,windows server 服务器不支持. package com.lx.ftp; import java.io.File; import ...

  6. js获取浏览器类型进行判断

    本文为webuploader.js中学习心得,感谢开源,从中加入了ie的edge判断 /** * @description 简单的浏览器检查结果. * * * `webkit` webkit版本号,如 ...

  7. what is a resolver

    resolver [rɪ'zɒlvə] 解析器 ViewResolver The ViewResolver provides a mapping between view names and actu ...

  8. js常见input校验

    //校验输入价格等,保留2位小数 function clearNoNum(obj){ obj.onkeyup = function(event){ var e = event || window.ev ...

  9. golang web sample

    一.学习想法 用两天的时间学习golang,但这次是先不看书的,直接写代码先. 我们常习惯边看书边学习写代码,但发现过程是比较缓慢的,所以我就先想写代码, 边写边查.就我们所知,web app一般是基 ...

  10. H5总结

    1.新增的语义化标签: <nav>: 导航 <header>: 页眉 <footer>: 页脚 <section>:区块 <article> ...