zoukankan      html  css  js  c++  java
  • 由浅入深学“工厂模式”(2)

     3.4 工厂方法

    有了简单工厂模式后,已经给我们带来了一些好处,但是还存在一些问题,如果我们又多了一个影像家电产品MP4之后,我们可以使MP4类从VideoWiring派生,但是却要修改Create类的代码使它能够生产出MP4这个产品来。不好的地方就在于,我们每次多一个产品的时候都需要修改Create而不是保持原来的代码不修改仅仅进行一种扩展。在Create类中修改不是每次都简单的多一个Case语句就能够解决问题。因为Create类中还封装了创建对象的逻辑,有可能还需要修改这些逻辑。这就违反了面向对象设计中一个很重要的原则“开-闭”原则。

     

    “开-闭”原则the Open Closed Principle OCP

    在面向对象设计中,如何通过很小的设计改变就可以应对设计需求的变化,这是令设计者极为关注的问题。开闭原则就是软件实体在扩展性方面应该是开放的而在更改性方面应该是封闭的。这个原则说的是,在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使得变化中的软件系统有一定的稳定性和延续性。因此在进行面向对象设计时要尽量考虑接口封装机制、抽象机制和多态技术。

     

    前边设计(简单工厂)中存在的问题就是它分装了创建不同对象的逻辑,当有新的产品的时候不易扩展。在开闭原则的指导下我们考虑如何重新修改前边的设计,我们要尽量使用抽象机制和多态技术。我们放弃对创建不同对象的逻辑的封装,也采用类似产品的方式,抽象出抽象工厂,具体工厂,具体工厂从抽象工厂派生,每个具体工厂中生产一种具体的产品。“太棒了,告诉你,你的这个想法就是工厂方法模式”。

     

    下面使用工厂方法模式修改前边的设计:

     

    public abstract class Create
    {
        
    public abstract VideoWiring factory();
    }


    public class DVDCreate: Create 
    {
        
    public override VideoWiring factory()
        
    {
            
    return new DVD();
        }

    }


    public class VCDCreate: Create 
    {
        
    public override VideoWiring factory()
        
    {
            
    return new VCD();
        }

    }

    VideoWiring、DVD、VCD三个类的代码和前边的相同,下面我们看看在客户端如何使用。

            private void PlayVideo()
            
    {
                VideoWiring dvd,vcd;
                Create dvdCreate,vcdCreate;
                dvdCreate
    =new DVDCreate();
                dvd
    =dvdCreate.factory();
                Play(dvd);
                vcdCreate
    =new VCDCreate();
                vcd
    =vcdCreate.factory();
                Play(vcd);
            }

       
    下面我们考虑需要扩展一个新的产品MP4的时候如何处理。


    我们来看看增加的代码:

    public class MP4Create: Create 
    {
        
    public override VideoWiring factory()
        
    {
            
    return new MP4();
        }

    }


    public class MP4: VideoWiring 
    {
        
    public override string PlayVideo()
        
    {
            
    return "正在播放MP4";
        }

    }


    我们再看看客户端代码:

            private void PlayVideo()
            
    {
                VideoWiring dvd,vcd;
                Create dvdCreate,vcdCreate;
                dvdCreate
    =new DVDCreate();
                dvd
    =dvdCreate.factory();
                Play(dvd);
                vcdCreate
    =new VCDCreate();
                vcd
    =vcdCreate.factory();
                Play(vcd);
        
                
    //下面是新增的代码
                VideoWiring mp4;
                Create mp4Create;
                mp4Create
    =new MP4Create();
                mp4
    =mp4Create.factory();
                Play(mp4);

            }


    我们可以看出使用了工厂方法模式后,很好的满足了开闭原则,当我们增加了一个新的产品MP4的时候没有修改原来的代码,而仅仅是对原来的功能进行扩展系统便有了MP4这个产品的功能。

     

    将工厂方法模式推广到一般情况:


    角色说明:

    抽象工厂(Creator):定义具体工厂的接口,所有的创建对象的工厂类都必须实现这些接口。

    具体工厂(ConcreteCreator):具体工厂包含与应用密切相关的逻辑。复杂创建具体的产品。

    抽象产品(Product):所有产品的基类。

    具体产品(ConcreteProduct):实现抽象产品申明的接口。工厂方法模式所创建的每个对象都是某个具体产品的实例。

      

    工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。这个核心类则成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。这种进一步抽象化的结果,使这种工厂方法模式可以用来允许系统在不修改具体工厂角色的情况下引进新的产品。

    (未完代续)..........

  • 相关阅读:
    C++内置类型对象之间的转换
    快速排序
    面试题7:用两个栈实现队列
    面试题6:重建二叉树
    poj 3264(线段树)
    poj 3038
    poj 并查集
    poj 1270(toposort)
    poj 2503(字符串)
    poj 3687(拓扑排序)
  • 原文地址:https://www.cnblogs.com/hobe/p/266749.html
Copyright © 2011-2022 走看看