C#面向对象编程及三大特性(二)

1、继承关系实现多态:一种调用,多种实现。
    1)多态:隐藏基类 —new 则隐藏,隐藏看类型(来决定调用父类还是子类的方法):
	  条件:父类子类写同名方法,子类方法名前加new(可以不加new)
      结果:对象的类型是子类则调用子类方法;是父类则调用父类方法
	  
    2)多态:重写 —over重写,重写只管新(调用新重写的方法):
     条件1: 继承、里氏转换原则,且父类和子类有同名的方法
		     在父类方法前加上virtual,在子类方法前加上override
     结果:  实现用父类对像调用子类方法
    3)隐藏基类应用:重写的子类调用自定义方法,不重写的继承父类方法,实现多态
	  父类提供ToString方法,子类继承下来,可以直接调用ToString方法。
      不重写:如果子类,没有提供ToString方法,那么直接使用object提供的。
      重写:如果用户提供了ToString方法,那么调用时,就可以调用自定义的方法。
           (开放封闭原则:对扩展开放,对修改封闭。)
    4)重写方法实例:父类根据指向的子类不同,调用不同子类的方法,实现多态。
  
View Code
class Program
    {
        static void Main(string[] args)
        {
            Father f = null;
            Console.WriteLine("你要使用什么元件?(1、手机;2、灯)");
            switch (Console.ReadLine())
            {
                case "1": f = new Phone("手机"); break;
                case "2": f = new Light("Usb灯"); break;
            }
            f.Usb();
        }
    }
    class Father
    {
        string name;
         ---此处省略数行---
        public virtual void Usb()
        {
            Console.WriteLine("父类方法!");
        }
    }
    class Phone : Father
    {
        public Phone(string name) : base(name)
        { }
        public override void Usb()
        {
            Console.WriteLine("正在充电!");
        }
    }
    class Light : Father
    {
        public Light(string name) : base(name)
        { }
        public override void Usb()
        {
            Console.WriteLine("亮灯!");
        }
    }

 

2、抽象类(难点)带有abstract的类
  抽象类是对一类事物或对象的抽象,统一了一类对象。
    ->抽象类当中的成员
		->抽象成员:方法、属性(、索引、事件声明)
		->非抽象成员,如Shape类中name
    ->抽象类的使用
		->抽像类就是为了实现多态的,在使用多态的地方几乎都可以使用抽象
		->抽象类是不能被实例化的,抽象类有构造方法(给非抽象成员赋初值)
   ->抽象成员的使用
	(1)抽象方法的使用 
			父类:[]abstract 返回类型 方法名() {}子类:[]override 返回类型 方法名() {}
	(2)抽象属性的使用  快捷键Shift+Alt+F10
	(3)抽象属性
		-> 抽象与自动属性,本质不同
			-> 自动属性,后台会有一个字段生成,体统会自动的添加对应的方法体
			-> 抽象属性,因为没有方法体,所以get,set中什么都没有
		-> 抽象与自动属性,结果不同
			-> 自动属性,get,set必须共存
			-> 抽象属性是可以有:只读、只写、可读可写之分的

3、抽象方法实现多态(简单的说与继承关系父类使用多态相似)
	不知道怎么实现;不需要实现,[public] abstract 返回类型 方法名( );	
   抽象方法必须在抽象类中,方法和类前面都有abstract
   抽象方法是为了实现多态,子类必须重写父类中的抽象方法
	public override 父类提供的方法名(){}
   特例:如果子类也是抽象的,可以不重写父类分抽象方法
   实例:形状类(抽象父类),圆形、长方形、正方形三个子类,实现父类调用子类方法求周长和面积

  

View Code
namespace AbstractClass
    {
        class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Shape[] s = { 
                                    new Circle("小圆",10),
                                    new Rectangle("小长",27.5,30),
                                    new Square("小方",100)
                                };
                    for (int i = 0; i < s.Length; i++)
                    {
                        s[i].Introduction();
                        Console.WriteLine("我的面积是:{0}",s[i].Area());
                        Console.WriteLine("我的周长是:{0}",s[i].Perimeter()); 
                    }
                    Console.ReadKey();
                }
            }
        }
    }

    abstract class Shape
    {
        //字段 属性
        string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        double pi = 3.14;

        public double Pi
        {
            get { return pi; }
            set { pi = value; }
        }

        //构造方法
        public Shape(string name)
        {
            this.name = name;
        }
        //抽象父类方法
        public abstract void Introduction();
        public abstract double Area();
        public abstract double Perimeter();
    }
    class Circle : Shape
    {
        //字段 属性 
        double r;

        public double R
        {
            get { return r; }
            set { r = value; }
        }
        
        //构造方法
        public Circle(string myname,double r1):base(myname)
        {
            r = r1;
        }

        //圆形子类方法
        public override void Introduction()
        {
            Console.WriteLine("我是一个圆:我叫{0}",Name);
        }
        public override double Area()
        {
            double area = 0;
            area = Pi * r * r;
            return area;
        }
        public override double Perimeter()
        {
            double perimeter;
            perimeter = 2 * Pi * r;
            return perimeter;
        }
    }

    
    class Rectangle : Shape
    {
        double length;

        public double Length
        {
            get { return length; }
            set { length = value; }
        }
        double width;

        public double Width
        {
            get { return width; }
            set { width = value; }
        }

        public Rectangle(string myname, double len,double wid)
            : base(myname)
        {
            length = len;
            width = wid;
        }

        public override void Introduction()
        {
            Console.WriteLine("我是矩形:{0}",Name);
        }
        public override double Area()
        {
            double area = 0;
            area = 2 * (length + width);
            return area;
        }
        public override double Perimeter()
        {
            double area = 0;
            area = length * width;
            return area;
        }
    }
    
    
    class Square : Shape
    {
        double a;

        public double A
        {
            get { return a; }
            set { a = value; }
        }

        public Square(string myname, double a1)
            : base(myname)
        {
            a = a1;
        }

        public override void Introduction()
        {
            Console.WriteLine("我是正方形:{0}",Name);
        }
        public override double Area()
        {
            double area = 0;
            area = 4 * a;
            return area;
        }
        public override double Perimeter()
        {
            double area = 0;
            area = a * a;
            return area;
        }
    }

 

4.1、接口(与使用抽象类类似)
接口是对能力和方法的抽象。
		[public] interface 接口名
		{
			// 接口成员
		}
		-> 接口成员
			-> 仅仅抽象能力,所以只有方法、属性、索引、事件声明
			-> 接口中的成员就相当于抽象类中的抽象成员
		-> 接口的定义和实现接口
			-> 定义接口方法不用写访问修饰符,默认public
			-> 子类继承自接口,实现接口中的方法时,写一个正常方法 (没有override)

4.2、接口的多继承性(有同名方法的处理)
(1)显式实现接口:
	通过显式实现接口的方式为特定的接口重写特定的方法,调用方法时根据变量所属的接口类型来选择相应的方法。
(2)调用接口:返回类型 接口名.方法名()显式实现的方法只能由接口调用
	接口类的对象优先调用显式实现接口的方法,缺少的情况,再调用非显式实现的方法。
	非接口类对象,只能调用非显式实现的方法,不能调用显式实现接口的方法。
	示例:
    class Duck4 : Duck,IJiaoable1, IJiaoable2
    {
        public void Jiao()
        {
            Console.WriteLine("普通实现接口");
        }
        void IJiaoable1.Jiao()
        {
            Console.WriteLine("显式实现接口IDuck1");
        }
        void IJiaoable2.Jiao()
        {
            Console.WriteLine("显式实现接口IDuck2");
        }
    }
	显式实现接口,Shift+Alt+F10生成,不加访问修饰符的(跟接口中一样)

5、接口实现多态:鸭子的实例-联合使用继承和接口实现多态
	不同鸭子游泳的方法不一样,所有鸭子都会游泳(继承)
	不同鸭子叫的方法不一样,有的还不会叫(接口)

View Code
    class Program
    {
        static void Main(string[] args)
        {
            Duck[] d = { new RealDuck(), new RubberDuck(),new WoodDuck()};
            for (int i = 0; i < d.Length; i++)
            {
                d[i].Swim();
                IJiaoable dk = d[i] as IJiaoable;
                if (dk != null) 
                {
                    dk.Jiao();
                }                      
            }
            Console.ReadKey();
        }
    }
    abstract class Duck
    {
       public abstract void Swim();
    }
    interface IJiaoable
    {
        void Jiao();
    }
    class RealDuck : Duck, IJiaoable
    {
        public override void Swim()
        {
            Console.WriteLine("我是真的鸭子,我会游泳!我游啊游~~~");
        }
        public void Jiao()
        {
            Console.WriteLine("我是真的鸭子,嘎嘎嘎!");
        }
    }
    class RubberDuck : Duck, IJiaoable
    {
        public override void Swim()
        {
            Console.WriteLine("我是橡皮鸭子,我会游泳!我游啊游~~~");
        }
        public void Jiao()
        {
            Console.WriteLine("我是橡皮鸭子,唧唧~~唧唧~~");
        }
    }
    class WoodDuck : Duck  //没有叫的方法,于是不实现IJiaoable接口
    {
        public override void Swim()
        {
            Console.WriteLine("我是木头鸭子,我会游泳!我游啊游~~~");
        }
}

6.多接口中有同名方法的调用 根据对象的接口类型,优先调用显式实现的该接口方法。 没有针对该接口的显式实现方法可调用时,调用非显式实现的方法。 显式实现接口,Shift+Alt+F10生成,不加访问修饰符的(跟接口中一样)
演示:普通实现接口和显示实现接口的调用
执行结果: Duck1,普通实现接口 Duck1,普通实现接口 Duck2,显式实现接口IJiaoableA Duck2,普通实现接口 Duck3,普通实现接口 Duck3,显式实现接口IJiaoableB Duck4,显式实现接口IJiaoableA Duck4,显式实现接口IJiaoableB 代码清单:
View Code
namespace 显式实现接口演示
{
    class Program
    {
        static void Main(string[] args)
        {
                Duck[] dk = { new Duck1(), new Duck2(),new Duck3(),new Duck4() };
                for (int i = 0; i < 4; i++)
                {
                    IJiaoableA dka = dk[i] as IJiaoableA;
                    if (dka != null)
                        dka.Jiao();

                    IJiaoableB dkb = dk[i] as IJiaoableB;
                    if (dkb != null)
                        dkb.Jiao();

                    Console.WriteLine();
                }

                Console.ReadKey();
        }
    }
    
    public abstract class Duck
    {
    }
    interface IJiaoableA
    {
        void Jiao();
    }

    interface IJiaoableB
    {
        void Jiao();
    }

    //普通实现接口:不针对两个接口分别写方法
    class Duck1 : Duck, IJiaoableA, IJiaoableB
    {
        public void Jiao()
        {
            Console.WriteLine("Duck1,普通实现接口");
        }
    }
    //普通实现接口+显式实现接口“IDuck1”
    class Duck2 : Duck,IJiaoableA, IJiaoableB
    {
        public void Jiao()
        {
            Console.WriteLine("Duck2,普通实现接口");
        }
        void IJiaoableA.Jiao()
        {
            Console.WriteLine("Duck2,显式实现接口IJiaoableA");
        }
    }
    //普通实现接口+显式实现接口“IDuck2”
    class Duck3 : Duck,IJiaoableA, IJiaoableB
    {
        public void Jiao()
        {
            Console.WriteLine("Duck3,普通实现接口");
        }
        void IJiaoableB.Jiao()
        {
            Console.WriteLine("Duck3,显式实现接口IJiaoableB");
        }
    }
    //普通实现接口+显式实现接口“IDuck1”+显式实现接口“IDuck2”
    class Duck4 : Duck,IJiaoableA, IJiaoableB
    {
        public void Jiao()
        {
            Console.WriteLine("Duck4,普通实现接口");
        }
        void IJiaoableA.Jiao()
        {
            Console.WriteLine("Duck4,显式实现接口IJiaoableA");
        }
        void IJiaoableB.Jiao()
        {
            Console.WriteLine("Duck4,显式实现接口IJiaoableB");
        }
    }
}

 

7、多态的应用原则
	多态实现方式:接口实现多态(对外)、抽象实现多态、父类实现多态(对内)
	开发过程:    定义接口—定义抽象—父类—子类,最终使用的是子类,给用户的是接口。
	              开发以抽象为主,能够抽象,尽量不要使用具体。
	接口的使用原则:单一功能,组合使用。
	抽象类是对一类事物的抽象,接口是对能力和方法的抽象。

8、简单工厂设计模式(使项目模块化,可以将不同模块分给不同的项目小组去完成和维护)
   思路:在Main方法中使用父类变量接收工厂方法的子类对象,实现了“统一调用,不同实现”的多态性。
   步骤:写一个父类(抽象、具体、接口),定义统一的执行标准
   写若干个子类,分别重写父类方法或实现接口的方法
   写一个Factory类,根据需求new出子类,赋给父类变量返回
   Mian方法中完成需求输入,调用Factory类方法,得到对象调用特定子类的方法。
   
演示:多态实现不同移动设备各自的读写操作 运行结果: 请选择您的设备类型: 输入编号或简码: 1.U盘(u/U), 2.Mp3(m/M), 3.移动硬盘(h/H) 1 U盘读数据中 U盘写数据中 请选择您的设备类型: 输入编号或简码: 1.U盘(u/U), 2.Mp3(m/M), 3.移动硬盘(h/H) 2 Mp3读数据中 Mp3写数据中 Mp3播放音乐中 请选择您的设备类型: 输入编号或简码: 1.U盘(u/U), 2.Mp3(m/M), 3.移动硬盘(h/H) 3 移动硬盘写数据中 移动硬盘读数据中 代码清单:
View Code
namespace IMoveMemableDemo
 {
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                //请用户插入移动设备
                Console.WriteLine("请选择您的设备类型:\n输入编号或简码: 1.U盘(u/U), 2.Mp3(m/M), 3.移动硬盘(h/H)");
                //根据用户输入调用“工厂模式”方法返回对象
                IMoveMemable device = Factory.GetDevice(Console.ReadLine());
                //使用设备 应用多态
                if (device != null)
                {
                    device.Read();
                    device.Write();
                    Mp3 mp3 = device as Mp3;
                    if (mp3!=null)
                        mp3.PlayMusic();
                }
                else
                {
                    Console.WriteLine("您输入的设备类型不存在!");
                }
                Console.WriteLine();
                Console.WriteLine();
            }
        }
    }
    
    public class Factory
    {
        public static IMoveMemable GetDevice(string name)
        {
            IMoveMemable device = null;
            switch (name)
            {
                case "1":
                case "u":
                case "U": device = new UDisk(); break;
                case "2":
                case "m":
                case "M": device = new Mp3(); break;
                case "3":
                case "h":
                case "H": device = new MHardDisk(); break;
                default:
                    break;
            }
            return device;
        }
    }
    
     public interface IMoveMemable
    {
        void Write();
        void Read();
    }

    public class UDisk : IMoveMemable
    {
        public void Write()
        {
            Console.WriteLine("U盘写数据中");
        }

        public void Read()
        {
            Console.WriteLine("U盘读数据中");
        }
    }

    public class Mp3 : IMoveMemable
    {
        public void Write()
        {
            Console.WriteLine("Mp3写数据中");
        }

        public void Read()
        {
            Console.WriteLine("Mp3读数据中");
        }

        public void PlayMusic()
        {
            Console.WriteLine("Mp3播放音乐中");
        }
    }

    public class MHardDisk : IMoveMemable
    {
        public void Write()
        {
            Console.WriteLine("移动硬盘读数据中");
        }

        public void Read()
        {
            Console.WriteLine("移动硬盘写数据中");
        }
    }
    
}

 


posted @ 2013-05-05 14:35  kinglong1984  阅读(275)  评论(0编辑  收藏  举报