设计模式学习[1]--大话设计模式中的工厂模式和策略模式的思考

这篇文章将要讲的是个人对于书上两个模式讲解的理解和思考。

大话中给了一个例子,做一个收款的例子,有三个输入:一件物品的单价,这件物品购买的数量,折扣选项。(这里只对一件物品进行计价)

操作起来就是获得一件物品的数量count和单价perprice,然后计算出总的费用total,同时根据折扣计算最终价格finaltotal。

折扣有三种:(1)正常不打折(什么也不做)(2)打八折(total×0.8)(3)满300减一百(finaltotal=total - int(total/300)*100)


如何实现呢?

可以先来思考一下,有几步(拿控制台命令来讲)

1 输入物品单价,数量和折扣选项

2 先计算出total价格,再根据不同的折扣选项进行分支运算得到不同的价钱返回


一、工厂模式实现方法

先不说工厂模式是什么,我们看看它是怎么做的。

abstract class CashSuper
{
	public abstract double acceptCash(double money); //现金计算虚基类
}

class Cash_normal: CashSuper
{
    public override double acceptCash(double money)
    {
    	return money;                    //啥都不干,原价返回

    }
}

class Cash_manjian: CashSuper
{
    public override double acceptCash(double money)
    {
    	return(money-int(money/300)*100)       //满300减100
    }
}

class Cash_dazhe: CashSuper
{
    public override double acceptCash(double money)
    {
    	return money* 0.8;                      //打八折
    }
}

class Factory
{
	 
	public CashSuper CashSuperCreator(string Type)    // 根据不同的选项,生产不同的类
	{
		switch(Type)
		{
			case normal:
			     Cash_normal cn=new Cash_normal();
			     cs=cn;
				 break;
			case manjian:
				 Cash_manjian cm=new Cash_manjian(300,100);
				 cs=cm;
				 break;
			case dazhe:
				 Cash_dazhe cd=new Cash_dazhe(0.8);
				 cs=cd;
				 break;
			default:
			     cout<<"input not supported";
			     break;
		}
		return cs;
	}

}


public void main(){
        //输入参数 
	cout<<"please input the consume type";
	string selectedType, 
	int count;
        double perprice,total,finaltotal;
	cin>>selectedType>>count>>perprice;
	//计算总价
        total=count*perprice;
        //通过不同的选择,由工厂生产不同的类
        CashSuper cs=CashFactory cf(selectedType);
	finaltotal=cs.acceptCash(total);
}

summary

上面的代码是最简单的实现

我们可以看到,其实这个问题的最关键点就在于怎么根据折扣选项的不同做选项。

工厂模式的方法是,分别提供现金计算的虚基类和实现类,以及工厂产生类。  现金计算只负责现金怎么算,工厂只负责怎么产。

形象点说现金计算只负责提供原材料,而工厂类则负责怎么产,也就是怎么进行类的对象实例化

工厂类其实都算不上各类,只是包含了一个普通成员函数,原材料输入参数和输出参数的种类都是人家别人的,它自己只负责实例化一下其他啥都不管的。

再罗嗦点来说,就是代工工厂,苹果人家设计了好东西,别人提供了原料,它只负责代工组装,输入的是人家的思想和原料,输出的还是人家苹果的成品,自己在产品上除了连made in China其他什么都留不下。

它只具有一层类的外壳,用数据结构来说,类包含了数据和操作方法,而工厂类则实质上只具有操作方法而已。


通过工厂模式,我们发现那些根据选项进行switch分支实例化这些逻辑语句都放到后台实现了。这就是工厂模式的好处。

但是这工厂模式有坏处,看这句话

CashSuper cs=CashFactory cf(selectedType);

我们看了后台知道这是Factory工厂类调用CashSuper方法生成了CashSuper子类的对象,又有Factory又有CashSuper的,能不能将这两个东西化减成一个东西出现在前台呢?

这是下下个部分三 要讲的。

反正我们至少知道通过工厂类,那些分支实例化的东西都可以用工厂类封装起来。




二、策略模式的实现。

abstract class CashSuper
{
	public abstract double acceptCash(double money);
}

class Cash_normal: CashSuper
{

    public override double acceptCash(double money)
    {
    	return money;

    }
}

class Cash_manjian: CashSuper
{
	Cash_manjian(double man, double jian)
	{

	}
    public override double acceptCash(double money)
    {
    	return(money-int(money/300)*100)

    }
}

class Cash_dazhe: CashSuper
{
 
	public override double acceptCash(double money)
    {
    	return money* 0.8;
    }

}

class Context
{
	//the inherits will automatically be converted to base class
	CashSuper cs;

	public Context(CashSuper cs_choice) //constructor
	{
		this.cs=cs_choice;		 
	}

	public CashSuper getResult(double total)
	{
		return cs.acceptCash(total);
	}

}


public void main(){
 
	cout<<"please input the consume type";
	string selectedType, 
	int count;
	double perprice,total,finaltotal;
	cin>>selectedType>>count>>perprice;
	total=count*perprice;

		switch(selectedType)
		{
			case "normal":
			         Context  context(new Cash_normal())
				 break;
			case "manjian":
				 Context  context(new Cash_manjian())
				 break;
			case "dazhe":
				 Context  context(new Cash_dazhe())  //我们可以看到整个客户端程序都是Context类,CashSuper 都没有出现。
				  break;                     //CashSuper的类的成员和方法已经被策略类Context给完完全全封装进去了
			default:
			     cout<<"input not supported";
			     break;
		}

	c_strategy.getResult(total);
}

summary
策略类的实现如上,

和工厂类只负责大生产实例化不一样,策略类已经把类的对象和操作方法包进去了。

在程序中我们可以看到整个客户端都是Context的身影,CashSuper类的内容几乎全进去了。

这也是我们为什么会说策略类用来封装类的,严严实实的我们从外边根本看不见。

策略类有自己的数据成员也即 CashSuper类的对象cs,因为有CashSuper对象和之前的虚方法,我们也可以编些函数操作这些对象,因此策略类能够使用类的对象和方法。

程序执行switch语句中,我们可以根据不同的折扣option,选择生成特定对象传到我们的Context类对象里面,由getResult方法可以使用CashSuper类的方法。


但是

有一点我们之前也说到:策略类已经把类的对象和操作方法包进去了,可以你看看程序,其实还是能够发现CashSuper的蛛丝马迹,在哪里呢?

Context  context(new Cash_normal())
你可以发现,策略类尽管把CashSuper的数据和方法都包含进去了,理论上应该没什么问题了,但是我们一旦实例化对象的时候,new Cash_normal这些CashSuper的小爪牙还是会出现的。

这个问题源于,策略类将类的数据和方法都封装了,但是实例化这个操作没有封装进来。。等等

实例化?

不是工厂模式擅长的么?于是我又要废话了。。。


三、策略模式和工厂模式结合


abstract class CashSuper
{
	public abstract double acceptCash(double money);
}

class Cash_normal: CashSuper
{

    public override double acceptCash(double money)
    {
    	return money;

    }
}

class Cash_manjian: CashSuper
{
	Cash_manjian(double man, double jian)
	{

	}
    public override double acceptCash(double money)
    {
    	return(money-int(money/300)*100)

    }
}

class Cash_dazhe: CashSuper
{
 
	public override double acceptCash(double money)
    {
    	return money* 0.8;
    }

}

class Context
{
	//the inherits will automatically be converted to base class
	CashSuper cs;

	public Context(string Type)    //Context不传对象进来了,而是根据折扣选择类型
       {                               //通过工厂模式来生成对应的对象。
		switch(Type)
		{
			case normal:
			     Cash_normal cn=new Cash_normal();
			     cs=cn;
				 break;
			case manjian:
				 Cash_manjian cm=new Cash_manjian(300,100);
				 cs=cm;
				 break;
			case dazhe:
				 Cash_dazhe cd=new Cash_dazhe (0.8);
				 cs=cd;
				 break;
			default:
			     cout<<"input not supported";
			     break;
		}
		 
	}

	public CashSuper getResult(double total)
	{
		return cs.acceptCash(total);
	}

}


public void main(){
 
	cout<<"please input the consume type";
	string selectedType, 
	int count;
	double perprice,total,finaltotal;
	cin>>selectedType>>count>>perprice;
	total=count*perprice;

	Context context(selectedType);
	context.getResult(total);


}

summary

在Context类里面,我们发现了,

Context不传对象进来了,而是根据折扣选择类型,而是工厂模式生成相应的对象。

于是我们在main程序中现在只看到了Context一个类,也看不到根据不同的折扣生成不同的对象这些乱七八糟的东西了。

这些都被我们用策略模式和工厂模式搞到内部了。



总结:

其实我们发现工厂模式和策略模式,其实根本不是像中文英文这样是完全分开的,他们叫模式,其实说实话就是针对某些特殊问题的对应方法。

工厂模式就是管生产的,精确说就是管CashSuper cs=new CashSuper()这类实例化的。这是对动态操作的封装。

策略模式就是管封装类的,可以把好多个类都搞进来。这是对静态东西的封装(类的对象和方法其实都是静态的,方法在那里,我不调用它还是静态的)

再从目的上来讲,

为什么要用工厂模式啊,因为这个类初始化这个,那个类实例化那个对象,各种实例化操作全交给工厂负责。

为什么要用策略模式啊,这个例子就需要用的,我们需要根据不同选择调用不同的现金计算类完成计算,那么用策略类和多态,我们就可以完成三个类调用的工作。所以类包含多个类并不是吃饱了没事干。

但是无论工厂模式还是策略模式,封装是目的,继承是基础,而多态则是机理保证。

三个normal,dazhe,manjian的子类其实都是通过cashsuper这个基类作为入口传进函数的,然后再在函数内部通过多态实现的。


PS。我都想不到,这么个简单的例子会有这么多话可以讲,不学不知道,不学则无术啊。如果你看到这里,希望对你有帮助



 

你可能感兴趣的:(设计模式)