简单工厂模式和策略模式都是三个业务子类继承抽象父类,通过传入参数到容器类(工厂模式的factory类,策略模式的Content类),选择对应的类进行行为操作。
其实,UML图的确从外形上看没多大区别,但是,本质却是大大不同。
简单工厂模式客户端传一个条件进工厂类,工厂类根据条件生成相应的对象并返回给客户端。实质是由一个工厂类根据传入的参数,动态决定应该创建并且返回哪一个产品类(这些产品类继承自一个父类或接口)的实例。
那么也就是说:
1、有已知的产品类
2、你无法准确的知道编译哪个产品类
3、需要在运行时决定创建哪个产品类
4、产品类不多
很明显看出,在创建对象上的灵活性高,但是工厂类只能创建可能会使用到的产品类,假如新添了产品类就得修改工厂类,这样就会违反开闭原则。
客户端创建一个Context对象a,创建策略对象并当做参数传递给a,然后客户端使用a方法通过某种方法得到想要的值返回给客户端。
策略模式是行为型模式,它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
在一段代码里,使用了逻辑控制(if-else,swich-case)来决定算法,算法有相似的方法和函数,就可以选择策略模式。
那么也就是说:
1、某方法里有多个条件语句,条件语句代码块里有许多行为过程。
2、其算法能封装到策略类
2、算法随意切换
3、算法与客户端隔离
这样一来,通过选择对应的策略类,作为参数传到Content类里,在运行时配置对应的算法。
如果在适合用策略模式的情况下用简单工厂模式,如果新增加策略就要修改工厂类,而这个可能会导致其他错误和比较繁琐,而如果使用了策略模式,只要将新增加的策略当做参数传递到Context类中即可。
先写一个人的接口类,有eat,run,wear 3个方法
public interface People {
public void eat();
public void run();
public void wear();
}
分别写两个实现类,一个是小明的实现类,一个是小红的实现类
public class Xiaoming implements People{
@Override
public void eat() {
System.out.println("小明吃饭");
}
@Override
public void run() {
System.out.println("小明跑步");
}
@Override
public void wear() {
System.out.println("小明穿衣");
}
}
public class Xiaohong implements People{
@Override
public void eat() {
System.out.println("小红吃饭");
}
@Override
public void run() {
System.out.println("小红跑步");
}
@Override
public void wear() {
System.out.println("小红穿衣");
}
}
简单工厂模式的代码
public class PeopleFactory {
public People getPeople(String name){
if(name.equals("Xiaoming")){
return new Xiaoming();
}else if(name.equals("Xiaohong")){
return new Xiaohong();
}
return null;
}
}
再来看下策略模式的代码
public class StrategySign {
private People people;
public StrategySign(People people){
this.people = people;
}
public StrategySign(String name){
if(name.equals("Xiaoming")){
this.people = new Xiaoming();
}else if(name.equals("Xiaohong")){
this.people = new Xiaohong();
}
}
public void run(){
people.run();
}
}
策略模式的两种构造方法都可以用,我多写了一种是为了让大家看到和工厂模式的区别和联系
然后我们通过测试类运行两种模式
@Test
public void testSign(){
PeopleFactory peopleFactory = new PeopleFactory();
People people = peopleFactory.getPeople("Xiaohong");
System.out.print("工厂模式-------------"); people.run();
StrategySign strategySign = new StrategySign("Xiaohong");
System.out.print("策略模式-------------");strategySign.run();
}
可以看到,两种设计模式的运行结果是一模一样的,那么区别到底在哪呢。
从工厂模式的代码中可以看到 工厂模式主要是返回的接口实现类的实例化对象,最后返回的结果是接口实现类中的方法,而策略模式是在实例化策略模式的时候已经创建好了,我们可以再策略模式中随意的拼接重写方法,而工厂模式是不管方法的拼接这些的,他只关注最后的结果,不注重过程,而策略模式注重的是过程。
用一个具体的例子可以看下,如果我想小红先吃饭再跑步再吃饭的话,那么我需要在测试类中写3种,而我只需要在策略模式的方法中直接定义即可。
可以看以下代码:
public class StrategySign {
private People people;
public StrategySign(People people){
this.people = people;
}
public StrategySign(String name){
if(name.equals("Xiaoming")){
this.people = new Xiaoming();
}else if(name.equals("Xiaohong")){
this.people = new Xiaohong();
}
}
public void run() {
people.eat();
people.run();
people.eat();
}
}
@Test
public void testSign(){
PeopleFactory peopleFactory = new PeopleFactory();
People people = peopleFactory.getPeople("Xiaohong");
System.out.print("工厂模式-------------"); people.eat();
System.out.print("工厂模式-------------"); people.run();
System.out.print("工厂模式-------------"); people.eat();
StrategySign strategySign = new StrategySign("Xiaohong");
System.out.print("策略模式-------------");strategySign.run();
}
下面有一段策略模式的代码。
using System;
using System.Net.Configuration;
namespace StrategyWithFactory
{
class Program
{
static void Main(string[] args)
{
Strategy strategyContent = null;
//伪代码。获取输入算法类型
EStrategy inputType = RequestInput();
if (inputType == EStrategy.A)
{
new Content(new StrategyA()).ContentInterface();
}
else if (inputType == EStrategy.B)
{
new Content(new StrategyB()).ContentInterface();
}
else if (inputType == EStrategy.C)
{
new Content(new StrategyC()).ContentInterface();
}
}
}
//算法抽象类
abstract class Strategy
{
public abstract void AlfoeirhmInterface();
}
//A算法类
class StrategyA : Strategy
{
public override void AlfoeirhmInterface()
{
Console.WriteLine("this is the StrategyA");
}
}
//B算法类
class StrategyB : Strategy
{
public override void AlfoeirhmInterface()
{
Console.WriteLine("this is the StrategyB");
}
}
//B算法类
class StrategyC : Strategy
{
public override void AlfoeirhmInterface()
{
Console.WriteLine("this is the StrategyC");
}
}
//上下文类
class Content
{
private readonly Strategy _strategy;
public Content(Strategy strategy)
{
_strategy = strategy;
}
public void ContentInterface()
{
_strategy.AlfoeirhmInterface();
}
}
//算法枚举
enum EStrategy
{
A = 1,
B = 2,
C = 3
}
}
上面的代码是策略模式的原型,假如Main函数是客户端,那么以后每加一个算法,都得在客户端修改一次,添加一个else if,引起了不必要的麻烦。那么,现在的情况,首先我们知道已有的ABC三种算法,但是我们又不确定运行时使用哪种算法,同时为了让客户端和业务逻辑代码隔离开,于是,我们可以将客户端的创建算法类的业务逻辑转移到Cotent类,并添加一个创建算法工厂的方法。
using System;
namespace StrategyWithFactory
{
class Program
{
static void Main(string[] args)
{
//伪代码。获取输入算法类型
EStrategy inputType = RequestInput();
new Content(inputType).ContentInterface();
}
}
//上下文类
class Content
{
private readonly Strategy _strategy;
public Content(EStrategy eStrategy)
{
_strategy = CreateFactory(eStrategy);
}
public Strategy CreateFactory(EStrategy eStrategy)
{
Strategy strategy = null;
switch (eStrategy)
{
case EStrategy.A:
strategy = new StrategyA();
break;
case EStrategy.B:
strategy = new StrategyB();
break;
case EStrategy.C:
strategy = new StrategyC();
break;
}
return strategy;
}
public void ContentInterface()
{
_strategy.AlfoeirhmInterface();
}
}
}
那么,策略和简单工厂的结合应用就实现了。
工厂模式中只管生产实例,具体怎么使用工厂实例由调用方决定,策略模式是将生成实例的使用策略放在策略类中配置后才提供调用方使用。
工厂模式调用方可以直接调用工厂实例的方法属性等,策略模式不能直接调用实例的方法属性,需要在策略类中封装策略后调用。
策略模式将不同的算法封装成一个对象,这些不同的算法从一个抽象类或者一个接口中派生出来,客户端持有一个抽象的策略的引用,这样客户端就能动态的切换不同的策略。 而工厂模式又分为简单工厂和抽象工厂和工厂模式 ,这些工厂是为了创建对象而出现的,工厂模式创建不同的单个对象,而抽象工厂是为了创建不同的一些列的对象或者操作
工厂模式类似英语考试的完形填空题(自己考虑填什么词、句子),策略模式类似信息匹配题(提前写好选择项,当你有多个填空时,直接选就好了,没有适合的就再多写几个选择项)。
参考:
https://blog.csdn.net/lmx125254/article/details/86625960
https://cloud.tencent.com/developer/article/1334971
https://blog.csdn.net/weixin_39928686/article/details/111124201