您的位置:首页 > 其它

设计模式之工厂方法模式和开放-封闭原则

2017-03-23 12:19 316 查看
设计模式之工厂方法模式开放-封闭原则

 

         以下所有仅供记录和参考,如有问题,请留言提出,感谢!转载注明出处。

 

         关于简单工厂模式参见之前写的设计模式之简单工厂模式

         在记录简单工厂模式的时候有提到这么一句话:简单工厂模式是工厂模式的特殊情况。其实话也不能这么说,研究了工厂方法模式之后,才发现,它是基于面向对象的“开放-封闭原则”而对简单工厂模式进行的改进。而且在记录简单工厂模式的那篇中,对于其缺点的描述说了一个“违反了‘高内聚责任分配原则’”,其实我也不懂这个原则。不过简单工厂模式确实违背了“开放-封闭原则”。

 

         那么,就先记录一下面向对象的“开放-封闭原则”(The Open-Closeed Principle),简称OCP

         所谓的开放-封闭原则(以下用OC原则代替)说的是:对于软件设计来说,无论是类,模块,函数等,可以扩展,但是不可以修改。意思是:对于扩展是开放的,对于修改是封闭的。举个例子:假如你设计实现了一个PC端的枪战游戏叫做“穿越毛线”,那么为了玩家能够对游戏保持新鲜感,那么就得每隔一段时间对游戏进行一次更新。在更新的时候,就不能违背“OC原则”。意思就是,你可以对游戏的源码进行扩展,但是不能对原有的代码进行修改(不含修复bug的情况)。如果你对源码进行了修改,那么就说明这款游戏在设计的时候没有遵循OC原则,同时这个软件的维护性和扩展性就显得很糟糕。所以这就要求了在软件设计的时候,需要遵循OC原则,为以后的版本升级扩展,以及后期的维护提供方便。

         针对于面向对象而言,OC原则提出:设计好一个类之后,就尽量不要再修改。但是 ,绝对的封闭是不可能做到的,不可能设计出来一个完美的永远不需要修改的类(假设设计的软件可以不断的更新)。那么,如何尽可能的设计出一个合理的封闭代码,我们可以在软件设计的时候,先假设变化不会发生,而当变化出现时,再使用继承和多态来对变化进行抽象隔离(创建父类,接口等,通过多态和继承对变化进行隔离)。当然,变化出现的越早越好,如果出现的晚了,用软件工程中的话来讲就是:问题出现的越晚,修复付出的代价越大。

         总而言之,OC原则的精神在于:面对新的需求时,我们只需要对增加代码,而不需要修改已经存在的代码。这样,才能体现出面向对象设计中的提到的,可维护性,可扩展性,可复用性,灵活性好。

         注:以上部分内容来自《大话设计模式》一书,感谢。

 

         大概记录了一下OC原则。结合此原则和简单工厂模式来看,继续“农民伯伯买化肥”例子,在例子中,如果需要添加一种新的化肥,首先,得添加这个新化肥的类,并让此类继承化肥类,这块的代码就是对原有代码的扩展,而没有修改,遵循了开放-封闭原则。然后还得在化肥工厂类(Factory)的switch-case选择结构中添加一组新的选择,那么这就意味着,打开了Factory类,进行了代码的修改,而这就违反了开放-封闭原则。那么,按照上面所说的,在变化出现的时候,使用继承和多态来进行抽象隔离。所以,在化肥工厂Factory类这块,可以仿照化肥类Fertilizer那样,抽象出一个总的工厂接口或者父类,然后将每种化肥重新封装成一个单独的类去继承工厂类。在需要化肥对象的时候,通过多态的方式进行对象的创建。这样就使用了继承和多态的性质对原有的变化进行了抽象隔离。如果现在需要重新添加一种新的化肥,那么只需要封装新化肥的类,让它继承工厂类就可以了。这就是只对原有代码进行了扩展,而没有修改代码,从而遵循了开放-封闭原则。

         下面用Java代码进行简单例子展示,依然使用在简单工厂模式中使用的例子:

化肥类,及其子类代码,这里添加了新的化肥有机肥(OrganicFertilizer):

public abstract class Fertilizer {
public abstract void getFertilizer();
}
public class K extends Fertilizer{
public void getFertilizer() {
System.out.println("got K");
}
}
public class N extends Fertilizer{
public void getFertilizer() {
System.out.println("got N");
}
}
public class P extends Fertilizer{
public void getFertilizer() {
System.out.println("got P");
}
}
public class OrganicFertilizer extends Fertilizer{
public void getFertilizer() {
System.out.println("got OrganicFertilizer");
}
}


工厂类,将原有的工厂改造成一个抽象类,而重新对每种化肥进行了封装,并继承工厂类:

public abstract class Factory {
public abstract Fertilizer creatFertilizer();
}
public class KFactory extends Factory{
public Fertilizer creatFertilizer() {
return new K();
}
}
public class NFactory extends Factory{
public Fertilizer creatFertilizer() {
return new N();
}
}
public class PFactoty extends Factory{
public Fertilizer creatFertilizer() {
return new P();
}
}
public class OrganicFertilizerFactory extends Factory{
public Fertilizer creatFertilizer() {
return new OrganicFertilizer();
}
}


再看看主类Farmer怎么写:

public class Farmer {
public static void main(String[] args) {
//Factory factory = new KFactory();					//利用多态,先创建出来对应的K化肥工厂实例
//Fertilizer fertilizer = factory.creatFertilizer();//工厂生产对应的K化肥对象
//fertilizer.getFertilizer();						//获取K化肥

Factory factory = new OrganicFertilizerFactory();	//如果需要更换化肥,就只需要改变这块new的工厂对象
Fertilizer fertilizer = factory.creatFertilizer();	//这里的代码不用改变
fertilizer.getFertilizer();							//这的代码也不用改变
}
}


 

         总结:从表面上来看,工厂方法模式似乎比简单工厂模式更加繁琐,因为没增加一种“化肥”,不仅要增加化肥类,还要添加一个对应化肥的工厂类。确实是更加麻烦了,但是工厂方法模式的优点在于,提高了代码的扩展性,灵活性,克服了简单工厂模式中需要修改代码的做法。这在面向对象编程中是特别重要的。

         除此之外,会发现,简单工厂模式和工厂方法模式都有一个共同点,那就是:在农民伯伯需要发生变化的情况下,还是需要对Farmer类进行修改,进而获取需要的化肥,这个修改在这两种工厂模式中是没有办法避免的,但是利用反射机制可以解决这种情况

,以后再说。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息