• 设计模式简单工厂、工厂方法、抽象工厂方法


    定义:

    工厂方法:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个.工厂方法让类把实例化推迟到子类

    抽象工厂模式:提供一个接口,用于创建相关或依赖具体对象的家族,而不需要明确指定具体类.

    要点:

      1. 所有的工厂都是用来封装对象的创建
      2. 简单工厂,虽然不是真正的设计模式,但仍不失位一个简单的办法,可以将客户程序从具体类中解耦出来
      3. 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
      4. 抽象工厂使用对象组合:对象的实现被实现在工厂接口所暴露出来的方法
      5. 所有工厂模式都通过减少应用程序和具体类之间的依赖进行松耦合
      6. 工厂方法允许类将实例化延迟到子类进行
      7. 抽象工厂创建相关的对象家族,而不需要依赖他们的具体类
      8. 依赖导致原则,指导我们避免依赖具体类型,而要尽量依赖抽象
      9. 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体编程

    个人理解:

    当我们在一个类中,使用另一个时,往往是通过new的方式new出来的这个类的实例,然后再进行使用.这其中即使我们使用的类有抽象类或接口,但仍免不了出现 absclass c = new subclass()这样一种情况.于是,就出现了耦合;实际上,我们要如何才能处理这样一个问题,实现解耦呢?

    想想我们在实际生活中接触的计算机,这个例子也许可以说明一点问题.计算机有主板,硬盘,光驱,内存,显示器,鼠标,键盘等几个零部件构成.我们在使用时是将硬盘、光驱、内存、显示器、鼠标、键盘插在了主板上,就可以使用了。而不是让主板new出一个硬盘,然后再使用硬盘,也不是让主板new出一个光驱,然后再使用光驱.而是让外界提供一个new好的硬盘,然后插给主板的硬盘接口上即可.

     如下:

    public class MainBoard
    {
        private HardDisk1 hd;
        public MainBoard()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }
    
        public MainBoard(HardDisk1 hd)
        {
            this.hd = hd;
        }
    
        public void ReadHD()
        {
            hd.Read();
        }
    }
    
    /// <summary>
    /// HardDisk1为某一个具体品牌的硬盘
    /// </summary>
    public class HardDisk1
    {
        public void Read()
        {
            HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>");
        }
    }
    
    ----------------------------------------
    
        protected void Page_Load(object sender, EventArgs e)
        {
            HardDisk1 hd = new HardDisk1();
            MainBoard mainboard = new MainBoard(hd);
            mainboard.ReadHD();
        }
    但是,此时还是没有解耦,主板是面向的HardDisk1来运行的.如何面向其他的硬盘呢.此时可以使用抽象类和简单工厂,如下:
    public class MainBoard
    {
        private HardDisk hd;
        public MainBoard()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }
    
        public MainBoard(HardDisk hd)
        {
            this.hd = hd;
        }
    
        public HardDisk Hd
        {
            get { return this.hd; }
            set { this.hd = value; }
        }
    
        public void ReadHD()
        {
            hd.Read();
        }
    }
    
    public abstract class HardDisk
    {
        public abstract void Read();
    }
    
    /// <summary>
    /// HardDisk1为某一个具体品牌的硬盘
    /// </summary>
    public class HardDisk1 : HardDisk
    {
        public override void Read()
        {
            HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>");
        }
    }
    
    /// <summary>
    /// HardDisk1为某一个具体品牌的硬盘
    /// </summary>
    public class HardDisk2 : HardDisk
    {
        public override void Read()
        {
            HttpContext.Current.Response.Write("HardDisk2 is reading.<br/>");
        }
    }
    
    public class HardDiskSimpleFactory
    {
        public HardDisk CreateHardDisk(string type)
        {
            if (type.ToLower() == "harddisk1")
            {
                return new HardDisk1();
            }
            else
            {
                return new HardDisk2();
            }
        }
    }
    
    ------------------------------------------------------
    
        protected void Page_Load(object sender, EventArgs e)
        {
            HardDiskSimpleFactory hdsf = new HardDiskSimpleFactory();
            HardDisk hd1 = hdsf.CreateHardDisk("harddisk1");
            MainBoard mainboard = new MainBoard(hd1);
            mainboard.ReadHD();
    
            HardDisk hd2 = hdsf.CreateHardDisk("harddisk2");
            mainboard.Hd = hd2;
            mainboard.ReadHD();
        }

    查看此时,主板和硬盘是否已经解耦,主板是不是没有new硬盘,也没有针对具体的硬盘进行读操作?此时我们使用的是简单工厂,简单工厂不是一个模式,而是我们在使用中养成的一个习惯.

    此时再看,主板和硬盘是已经解耦了,但是看看HardDiskSimpleFactory类是否违背了开放-封闭原则.

    开放-封闭原则是对扩展开放,对修改关闭,此时,如果我们新增加了一个硬盘类型HardDisk3的话,是不是又要对HardDiskSimpleFactory类进行修改呢?如果能避免再扩展类的同时,又对这个类进行修改?此时我们就要使用工厂方法模式.

    代码修改如下:

    public abstract class HardDiskFactory
    {
        public abstract HardDisk CreateHardDisk();
    }
    
    public class HardDisk1Factory : HardDiskFactory
    {
        public override HardDisk CreateHardDisk()
        {
            return new HardDisk1();
        }
    }
    
    public class HardDisk2Factory : HardDiskFactory
    {
        public override HardDisk CreateHardDisk()
        {
            return new HardDisk2();
        }
    }
    
    ------------------------------------------------
    
        protected void Page_Load(object sender, EventArgs e)
        {
            HardDiskFactory hdsf1 = new HardDisk1Factory();
            HardDisk hd1 = hdsf1.CreateHardDisk();
            MainBoard mainboard = new MainBoard(hd1);
            mainboard.ReadHD();
    
            HardDiskFactory hdsf2 = new HardDisk2Factory();
            HardDisk hd2 = hdsf2.CreateHardDisk();
            mainboard.Hd = hd2;
            mainboard.ReadHD();
        }

    此时,已经基本不再违背开放-封闭原则,如果我们现在有了新的硬盘类型HardDisk3,那我们该怎么办呢?

    //新增一个硬盘类型HardDisk3
    public class HardDisk3 : HardDisk
    {
        public override void Read()
        {
            HttpContext.Current.Response.Write("HardDisk3 is reading.<br/>");
        }
    }
    
    //新增一个工厂HardDisk3Factory
    public class HardDisk3Factory : HardDiskFactory
    {
        public override HardDisk CreateHardDisk()
        {
            return new HardDisk3();
        }
    }
    
    -------------------------------------------------
    
        protected void Page_Load(object sender, EventArgs e)
        {
            HardDiskFactory hdsf1 = new HardDisk1Factory();
            HardDisk hd1 = hdsf1.CreateHardDisk();
            MainBoard mainboard = new MainBoard(hd1);
            mainboard.ReadHD();
    
            HardDiskFactory hdsf2 = new HardDisk2Factory();
            HardDisk hd2 = hdsf2.CreateHardDisk();
            mainboard.Hd = hd2;
            mainboard.ReadHD();
    
    
            HardDiskFactory hdsf3 = new HardDisk3Factory();
            HardDisk hd3 = hdsf3.CreateHardDisk();
            mainboard.Hd = hd3;
            mainboard.ReadHD();
        }
    此时,我们添加了一个类型的硬盘,也不再修改原来的硬盘生成方法,从而遵循了开放封闭原则.
    如果我们再提出新的需求,即:我们购买品牌机,此时机器的主板,内存,硬盘,光驱等零部件都是由该品牌机的子工厂或相关原料工厂生产的,也就意味着
    我们需要同一系列的内存,硬盘,光驱等零件,那么我们就可以采用抽象工厂方法来解决这个问题.我们再次改造工厂,代码如下:
    首先是硬盘类,没有变化,如下:
    public abstract class HardDisk
    {
        public abstract void Read();
    }
    
    /// <summary>
    /// HardDisk1为某一个具体品牌的硬盘
    /// </summary>
    public class HardDisk1 : HardDisk
    {
        public override void Read()
        {
            HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>");
        }
    }
    
    /// <summary>
    /// HardDisk1为某一个具体品牌的硬盘
    /// </summary>
    public class HardDisk2 : HardDisk
    {
        public override void Read()
        {
            HttpContext.Current.Response.Write("HardDisk2 is reading.<br/>");
        }
    }
    下面我们新建光驱类,光驱肯定也不只一种类型,可能一个品牌就会有一种类型的光驱:
    public abstract class CD_ROM
    {
        public abstract void Read();
    }
    
    public class CD_ROM1 : CD_ROM
    {
        public override void  Read()
        {
     	    HttpContext.Current.Response.Write("CD_ROM1 is Reading CD.<br/>");
        }
    }
    
    public class CD_ROM2 : CD_ROM
    {
        public override void  Read()
        {
     	    HttpContext.Current.Response.Write("CD_ROM2 is Reading CD.<br/>");
        }
    }

    此时,我们再次建立工厂类,此时的工厂要是生产的话,需要生产一个系列的产品,具体如下:

    public abstract class HardWareFactory
    {
        public abstract HardDisk CreateHardDisk();
        public abstract CD_ROM CreateCD_ROM();
    }
    
    public class HardWare1Factory : HardWareFactory
    {
        public override HardDisk CreateHardDisk()
        {
            return new HardDisk1();
        }
    
        public override CD_ROM CreateCD_ROM()
        {
            return new CD_ROM1();
        }
    }
    
    public class HardWare2Factory : HardWareFactory
    {
        public override HardDisk CreateHardDisk()
        {
            return new HardDisk2();
        }
    
        public override CD_ROM CreateCD_ROM()
        {
            return new CD_ROM2();
        }
    }
    重新再写主板类:
    public class MainBoard
    {
        private HardDisk hd;
        private CD_ROM cdrom;
    
        public MainBoard(HardDisk hd,CD_ROM cdrom)
        {
            this.hd = hd;
            this.cdrom = cdrom;
        }
    
        public HardDisk HD
        {
            get { return this.hd; }
            set { this.hd = value; }
        }
    
        public CD_ROM CD_ROM
        {
            get { return this.cdrom; }
            set { this.cdrom = value;}
        }
    
        public void ReadHD()
        {
            hd.Read();
        }
    
        public void ReadCD_ROM()
        {
            cdrom.Read();
        }
    }

    这是,我们的客户端再调用时,如下:

        protected void Page_Load(object sender, EventArgs e)
        {
            HardWareFactory hwf = new HardWare1Factory();
            HardDisk hd = hwf.CreateHardDisk();
            CD_ROM cdrom = hwf.CreateCD_ROM();
    
            MainBoard board = new MainBoard(hd, cdrom);
            board.ReadCD_ROM();
            board.ReadHD();
    
    
            hwf = new HardWare2Factory();
            hd = hwf.CreateHardDisk();
            cdrom = hwf.CreateCD_ROM();
    
            board = new MainBoard(hd, cdrom);
            board.ReadCD_ROM();
            board.ReadHD();
        }

    页面效果如下:

    image

    至此,关于三个工厂,已经介绍完了.胡乱小结一下:

    简单工厂:封装变化,创建对象,返回给客户使用.

    工厂方法:封装变化,创建对象,返回给客户使用.同时避免了违反开放-封闭原则.

    抽象工厂:创建一系列的对象,将创建好的对象返回给客户使用,同时遵循了开放-封闭原则.

  • 相关阅读:
    Python什么是二次开发的意义?python在.net项目采用
    斐波那契数
    Java 兑换ObjectC代码
    第18本:《整理的艺术》
    第16本:《视觉繁美:信息可视化方法与案例解析》
    第14本:《李鸿章传》
    第10本:《设计心理学》
    第17本:《代码的未来》
    第15本:《视不可当----信息图与可视化传播》
    第13本:《富爸爸,穷爸爸》
  • 原文地址:https://www.cnblogs.com/oneword/p/1556686.html
Copyright © 2020-2023  润新知