zoukankan      html  css  js  c++  java
  • 从子类化到工厂模式

      工厂模式是最常用和最简单的设计模式,其与以抽象、多态为特征的oo结合的十分紧密,在以前的一篇介绍mvc框架切入点的随笔中对这一点就有过论证。

      首先看一段代码

    abstract class Animal {
        public abstract void Shout();
    }
    
    class Dog : Animal {
        public override void Shout() {
            Console.WriteLine("wangwang");
        }
    }
    
    class Cat : Animal {
        public override void Shout() {
            Console.WriteLine("miao");
        }
    }
    
    //...
    public static void Main() {
        var name = Console.ReadLine();
        Animal animal = null;
        if (name == "Dog") animal = new Dog();
        else if (name == "Cat") animal = new Cat();
        animal.Shout();
    }
    

      很简单的实例,却充满了臭味,为了实现功能,调用者必须熟知Animal的整个继承体系。那么应该怎么改进呢?启用工厂模式,看下面的代码:

    public static class AnimalFactory {
        public static Animal Create(String name) {
            if (name == "Dog") return new Dog();
            else if (name == "Cat") return new Cat();
    
            return null;
        }
    }
    
    public static void Main() {
        var animal = AnimalFactory.Create(Console.ReadLine());
        if(animal!=null) animal.Shout();
    }
    
    //或者去掉Animal的abstract,使用基类实现工厂
    class Animal {
        private Animal() { }
        public virtual void Shout() { }
        public static Animal Create(String name) {
            if (name == "Dog") return new Dog();
            else if (name == "Cat") return new Cat();
    
            return null;
        }
    }
    

      好了,不同层之间的分离完成,基本的目的已经达到,那么就完了么?还没,当子类扩张的时候,我们必须进入工厂内部去修改分支语句,这就违反了封闭开放原则。那么怎么改进呢?使用表格,实现如下:

    public static class AnimalFactory {
        static AnimalFactory() {
            children.Add("Dog", typeof(Dog));
            children.Add("Cat", typeof(Cat));
        }
    
        public static Animal Create(String name) {
            if (children.Keys.Contains(name))
                return Activator.CreateInstance(children[name]) as Animal;
    
            return null;
        }
    
        public static Dictionary<String, Type> children;
    }
    

      上面的实现是一种最简单的基于表格驱动的工厂模式,内部基于反射Type的表格的数据来源于自己手动去注册。基于表格驱动的工厂模式的核心在于表格数据的来源,其来源有下面几种:

      1).手动注册,如上面显示的;

      2).使用attribute,然后通过放射,在静态初始化函数中对相关的程序集进行扫描,进行表格的填充,简单显示如下:

      

    public class AnimalMapAttribute : Attribute {
        public String Name { get; set; }
    }
    
    [AnimalMap(Name="cat")]
    public class AnimalMapAttribute : Attribute {
        public String Name { get; set; }
    }
    

      

      3).使用配置文件进行键值对的登记,然后解析配置文件进行加载,还记得asp.net mvc配置文件中对handler进行注册的 

        <add name="xx" path="*." verb="xx" type="xx" />

       语句么,使用配置文件进行注册的方式大抵如此。

      具体的实现模式按照需求选择,如果子类数量固定或者代码可以很方便进行修改和编译,使用分支语句就行,因为基于表格驱动的模式需要用到反射。其实还有一种情况也可以勉强成为工厂模式,如下

    class Animal {
        private Animal() { }
        public virtual void Shout() { }
    
        public static Animal Cat {
            get {
                return new Cat();
            }
        }
    
        public static Animal Dog {
            get {
                return new Dog();
            }
        }
    }
    

      将子类以静态属性的形式写于基类里面,然后外部通过Animal.Cat进行访问就行。BCL中的Encoding类就是以这种方式暴露得编码类接口。同上,适用于子类固定的情形。

  • 相关阅读:
    JSON
    必须使用角色管理工具 安装或配置microsoft.net framework 3.5
    Backbone.js之view篇(三)
    MSDN Webcast 资源
    JS获取select 当前选种值
    我理解的js闭包
    javascript基础温习(一)
    js动态添加删除行
    delphi 版 sqlHelper第二版
    2012末日没有到来,继续我们的2013
  • 原文地址:https://www.cnblogs.com/wangjieas/p/3274150.html
Copyright © 2011-2022 走看看