zoukankan      html  css  js  c++  java
  • 15-01-18 C# 面向对象 13

    要进入debug文件,除了右键进入资源管理器之外,也可以在解决方案资源管理器右上方,点击显示全部文件按钮,会列出当前项目的文件列表,把要放的文件放入debug即可;

    多态的好处 1,减少代码量 2.屏蔽各个子类之间的差异,写出通用的代码;

    C#中的访问修饰符;

    public 公开的,公共的

    private 私有的,只能在当前类的内部访问

    protect 受保护的, 只能在当前类的内部以及该类的子类中访问,

    internal 只能在当前项目中访问,在同一项目中,internal和public的访问修饰符是一样的,

    protected inrernal  它的权限是protected权限加上internal的权限;

    修饰类的访问修饰符只有两个,public internal,如果不写类的访问修饰符,默认是internal,表示只有在当前项目中才能访问这个类,出了这个项目就访问不到了,因此我们为了 让在别的项目里也能访问到这个类的话,我们在建类的时候在类的前面加上public

    internal的权限和protected相比,在同一个项目中。Internal的权限要比protected大,但是一旦垮了项目,protected的权限要比internal的权限大,因为不同项目之间依然存在继承关系, internal访问不到了,但是由于继承关系,protected成员依然可以跨项目访问,(跨项目的时候1要添加引用,2要添加命名空间);

    在命名空间中定义的元素无法显示的声明为private,protected,protected internal;

    类中的成员五个访问修饰符都可以定义;

    可访问性不一致,子类的访问权限不能高于父类的访问权限;原因是会暴漏父类的成员;

    简单工厂设计模式 设计这个项目的一种方式; 有一个牛人把我们写程序当中经常会遇到的问题,没一个问题都写成了一个解决方案;这一个解决方案就是一个设计模式,有23个设计模式;如果把23种设计模式从头到尾敲一遍就是大牛了, 设计模式帮助我们解决在日常开发中遇到的问题,

    简单工厂设计模式最核心的就是工厂,这个工厂最后根据用户的输入来返回一个(笔记本对象),但是用户输入的东西是不知道的,只能给他返回一个父类,但是父类里面装的是子类的对象,

    重写父类的方法的时候,子类的方法名字和父类被重写方法的名字是一样的,

    public abstract class NoteBook

    {   

      public abstract void SayHello();

    }

    public class Lenovo : NoteBook

    {   

      public override void SayHello()   

      {       

        Console.WriteLine("我是联想");

      }

    }

    public class IBM : NoteBook

      {   

        public override void SayHello()   

         {       

          Console.WriteLine("我是IBM");  

          }

      }

    public class Acer : NoteBook

      {   

        public override void SayHello()   

        {       

          Console.WriteLine("我是宏基");

          }

    }

    public class Dell : NoteBook

      {   

        public override void SayHello()   

         {       

          Console.WriteLine("我是戴尔");   

          }

      }

    public class Test

    {   

    public static NoteBook GetNoteBook(string brand) //简单工厂的核心,根据用户的输入创建对象赋值给父类;其实还有一个核心的还是用抽象类实现了多态;     

     {      

         NoteBook nb = null;      

        switch(brand)

          {      

          case"Lenovo":

            nb = new Lenovo();       

            break;      

          case"IBM":

            nb = new IBM();       

            break;      

           case"Acer":

            nb = new Acer();       

            break;      

          case"Dell":

            nb = new Dell();       

             break;  

        }      

        return nb;                //简单工厂最核心的代码部分;

      }

    }

    string brand = Console.ReadLine();

    NoteBook nb = GetNoteBook(brand);

    nb.SayHello();

    值类型:int double char decimal bool enum struct

    引用类型:string 数组 自定义类 集合 object 接口

    值类型在复制的时候,传递的是这个值的本身,

    person p1 = new person();

    p1.Name = "张三";

    person p2 = p1;     

    //这行代码表示p1,p2指向同一个对象(p1的new person());现在只要改变p1或者p2的其中任何一个,(p1的new person())其中另外一个值就会变;                    

    //简单的说,p1和p2指向同一块内存,这个时候只要改变p1,那么p2也跟着改变,只改变p2,那么p1也跟着改变; p2.Name = "李四"; //把p2变成了李四,那么p1也成了李四; Console.WriteLine(p1.Name); 输出的是"李四";

    引用类型在复制的时候,传递的是对这个对象的引用(地址);

    person p = new person();

    p.Name = "张三";

    Test(p);

    Console.WriteLine(p.Name);  //p.Name 为李四;

    public static void Test(person pp)

    {  

     person p = pp;  

     p.Name = "李四";

    }

    不管是形参还是实参都是实实在在在内存中占空间的,

    string s1 = "张三";

    string s2 = s1;

    s2 = "李四";

    Console.WriteLine(s1);  //张三 

    虽然是引用类型,但是字符串的不可变性;

    Console.WriteLine(s2);  //李四

    int number = 10;

    TestTwo(number);

    Console.WriteLine(number);   //输出10;

    public static void TestTwo(int n)

    {  

    n+=10;

    }

    int number = 10;

    TestTwo( ref number);

    Console.WriteLine(number);   //输出20;

    public static void TestTwo( ref int n)

    {

      n+=10;

    }

    ref能够把一个变量,以参数的形式带到一个方法中进行改变,再将改变完成后的值带出方法,

    ref的原理是把值类型的值传递变为引用传递,使得两个值类型共占一块内存空间(地址);

    要看变量在栈上的地址,设个断点,运行,然后在即时窗口输入&变量名,按回车;

    序列化:就是将对象转换为二进制;

    反序列化:就是将二进制转换为对象,

    序列化和反序列化的作用:传输数据;

    在网络中不管传输什么内容,先把传输的内容二进制,对方接收到的也是二进制,它需要干另外一件事就是反序列化;把这个二进制 反序列化为对象;

    public class Person

    {    

      private string _name;       

      public string Name  

         {        

        get{return _name;}        

        set{_name = value} 

         }        

         private int  _age;    

         public int Age;

        {       

         get{return _age;}    

         set{_age = value}   

        }         

         private char  _gender;    

         public char Gender   

        {      

          get{return _gender;}     

          set{_gender = value}   

        }

    }

    序列化的第一步 1.将这个类标记为可以被序列化的,在一个类的上面写上[Serializable]指示一个类可以被序列化,此类不可以被继承;

    只有被[Serializable]标记的类创建出来的对象   才能被序列化;

    person p = new person();

    p.Name = "张三";

    p.Age = 19;

    p.Gender = '男';

    using(FileStream fsWrite = new FileStream(@"C:UsershhsDesktop1.txt",FileMode.OpenOrCreate,FileAccess.Write))

    {    //开始序列化对象   

        BinaryFormatter bf = new BinaryFormatter();  

        bf.Serializa(fsWrite,p);

    }

        Console.writeline("序列化成功");

      //反序列化

       Person p;

    using(FileStream fsRead = new FileStream(@"C:UsershhsDesktop1.txt",FileMode.OpenOrCreate,FileAccess.Read))

    {   

        BinaryFormatter bf = new BinaryFormatter();  

        p = (Person)bf.Deserializa(fsRead);

    }

    Console.WriteLine(p.Name);

    Console.WriteLine(p.Age);

    Console.WriteLine(p.Gender);

    学一个东西一定要知道它是干嘛用的;

    在一个命名空间下不允许定义一个重名的类,也不允许在一个类中定义重名的方法(前提是它们没有重载)

    我们有的时候必须要在一个命名空间下定义重名的类,比如三个人共同做一个项目,这时候都要写person类,

    public partial class Person

    {    

    }

    public partial class Person

    {    

    }

    //这两个都是person类的一部分,共同组成了person类,这样的话就可以同时对person类进行编程,而且一个部分类的成员在另一个部分类里面全都可以访问;  但是部分类里面不允许有重名的方法(不包括重载)

    public sealed class Person   //密封类最大的特点就是不能被继承;但是能继承别的类;

    {   

    }

    重写toString()方法; 如果直接对象.ToString(),那么打印出来的是它的命名空间;

    所有的类都能ToString(),因为所有类都直接或间接继承object类,ToString()是object类的方法;

    因为子类不能调用父类的抽象方法,但是子类可以调用父类的虚方法,所以ToString()是虚方法,因为我们可以重写它,子类可以重写父类的虚方法;(当然子类也可以重写父类的抽象方法)

    public class Person

    {  

      public  override string Tostring()

        {  

           return  "Hello World";  

        }

    }

    重写了Tostring()方法,但是只是Person类的ToString();其他类的ToString()依旧没变;

    接口:

    public class Person

    {  

         public void CHLSS()  

        {    

          Console.WriteLine("我是人类,我可以吃喝");  

        }

    }

    //public class NBAPlayer

    //{

    //  public void KouLan()

    // {

    //     Console.WriteLine("我可以扣篮");

    //  }

    }

    public class Student : Person,IKouLanable

    {  

        public void KouLan()  

        {   

          Console.WriteLine("我也可以扣篮");  

        } 

    }

    //由于Student继承了Person类,因此他可以吃喝,但是同时他也想实现可以扣篮,由于继承具有单根性,不能既继承Person,又继承NBAPlayer,这时候我们可以考虑将NBAPlayer定义成一个接口

    public  interface IKouLanable 

    //以I开头以able结尾表示一种能力

    {  

      void KouLan();

    }

    定义成接口之后,Student就可以既继承Person,又可以继承NBAPlayer接口了,

    一个类继承了接口,必须要实现这个接口的成员,快速实现Alt+shift+F10

    什么时候需要用到接口, 1.类需要实现多继承;因为类是不允许多继承的;

    接口就是一个规范,能力;

    接口:

    [public] interface I...able

    {  

    成员;

    }

    public interface IFlyable

    {  

    void Fly(); //比抽象方法更省事;

    接口中的成员不允许添加访问修饰符;默认就是public,接口中没有方法体,类中成员不添加默认就是private               

    //抽象类中普通的方法可以有方法体,但是抽象函数不可以,但是在接口中不允许写有方法体的成员;               

    //接口中不能包含字段;接口不是用来存储数据的,存储数据用类来存,  

    string Test();  

    string Name  

    {    

     get;    //自动属性;  接口中能写方法,但是不能有方法体,属性的本质是get,set方法,因为自动属性没有get,set方法体,因此,接口中可以有自动属性,  

       set;    //get和set本质上也是函数,因此这个自动属性和上面的fly没有区别;

       }

    }

    private string _name;

    public string Name

    {  

       get{return _name;}

       set{_name = value;}

    }

    public int Age

    {  

      get;  

          set;

    }

    自动属性,虽然我们没有给它写字段,但是在编译的时候会自动的给我们生成一个字段; 自动属性和普通属性的区别,一个有字段,有方法体 ;一个没有字段,没有方法体; 自动属性的缺点,不能在属性里面进行值的限定了,不允许写方法体,那么要对值进行限定就要使用构造函数了;各有各的好处; 自动属性本质上是两个函数,

    接口中可以有方法和属性,还可以有索引器(索引器还没学过;)这三个东西本质上都是方法;接口中只能有方法;

    接口是一种规范,只要一个类继承了一个接口,这个类就必须实现这个接口中所有的成员;

    一个类中,去实现接口中的方法,没有override,有override是重写;

    为了多态,接口不能被实例化,也就是说,接口不能new(不能创建对象);

    抽象类,静态类,接口不能被实例化;抽象类,接口由于没有对方法进行实现,因此即使创建了对象也没有意义; 因此要实现多态的话,要去指向一个子类对象; 

    //实现多态的时候,3种方法一般都是父类对象装子类;三种方式都是在继承的基础上实现多态;

    IFlyable fly = new Person();

    fly.Fly();

    public class Person:IFlyable

    {  

    public void Fly()  

      {    

       Console.WriteLine("人类在飞");  

     }

    }

    public class Bird:IFlyable

    {  

       public void Fly()  

        {    

           Console.WriteLine("鸟类在飞");  

        }

    }

    public interface IFlyable

       {  

         void Fly();

       }

    接口中的成员不能加“访问修饰符”,接口中的成员访问修饰符为public,不能修改;

    接口中的成员不能有任何实现,这个很我们的抽象类当中的抽象函数是一样的,(都是光说不做,交给子类去做,接口只是定义了一组未实现的成员);

    接口中只能有方法,属性,索引器,事件,这四个本质上都是方法,不能有“字段”和构造函数;不能有字段是因为接口不是用来存储数据的,它表示一种规范,一种能力;

    因为接口不能创建对象,因此即使有构造函数没有用

    接口与接口之间可以继承,并且可以多继承;类就不能多继承;

    public interface M1

    {  

      void Test1();

    }

    public interface M2

    {  

      void Test2();

    }

    public interface M3

     {  

       void Test3();

     }

    public interface SuperInterface:M1,M2,M3

    {  

    }

    public class Car : SuperInterface  //继承一个大接口,他所继承的接口都要实现;

    {  

       public  void Test1();  

        {   

         }

       public  void Test2();  

        {   

        }

        public  void Test3();  

        {   

         }

    }

    接口并不能去继承一个类,而类可以继承接口(接口只能继承接口。而类既可以继承接口,也可以继承类)

    实现接口的子类必须实现该接口的全部成员;

    一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承了父类A,并实现了接口IA,那么语法上A必须写在IA的前面; class MyClass:A,IA{},因为类是单继承的.

    说是说面向对象的编程,但是很多情况下其实就是面向接口的编程;

    比如说手机中的天气预报,有很多个APP都有天气;但是这些数据源头是中央气象台; 中央气象台对外提供了一个接口,那么我只要实现这个接口中的成员,按照指定的要求去做,那么就可以得到天气信息;

    支付宝之前只有淘宝有,很多网站现在都有,因为也实现了接口,所以现在基本上就是面向接口编程;

    麻雀会飞, 鹦鹉会飞 鸵鸟不会飞 企鹅不会飞  直升机会飞

    用多态来实现虚方法,抽象类,接口;

    IFlyable fly = new YingWu()//new MaQue()//new Plane();

    fly.Fly();

    public class Bird

    {  

      public double Wings  

      {    

         get;   

         set;

       }

       public void EatAndDrink()   

       {      

           Console.WriteLine("我会吃喝");   

        }  

      }

    public class MaQue:Bird,IFlyable

      {  

         public void Fly()   

         {   

           Console.WriteLine("麻雀会飞");   

         }

     }

    public class YingWu:Bird,IFlyable,ISpeakable

      {

         public void Fly()   

          {   

            Console.WriteLine("鹦鹉会飞");  

           }      

        public void Speak()   

        {   

           Console.WriteLine("鹦鹉可以学人类说话");

        }

    }

    public class TuoBird:Bird

      {  

       }

    public class QQ:Bird

      {  

      }

    public class Plane:IFlyable

      {  

         public void Fly()

        {  

          Console.WriteLine("直升飞机转动螺旋桨飞行");  

        }

    }

    public interface IFlyable

       {

          void Fly();

       }

    public interface ISpeakable

       {  

        void Speak();

       }

    //显示实现接口就是为了解决方法的重名问题;

    public class Bird:IFlyable

     {  

         public void fly()  

         {   

            Console.WriteLine("鸟会飞");   

         }  

         void IFlyable.Fly()             //显示实现接口; 不允许加访问修饰符,类中的成员默认是private,接口中默认是public

        {   

          Console.WriteLine("我是接口的飞");    //这个其实跟抽象类一样,调用的是父类的函数,只不过在子类中重写了;  

        }    

      }

    public interface IFlyable

     {  

        void Fly();

    }

    Bird自己的方法和接口中的方法重名了,

    IFlyable fly = new Bird();

    fly.Fly();           //接口的飞  本质上访问的是接口的Fly,只不过接口的Fly被子类实现了;接口的Fly是public的

    Bird bird = new Bird();

    bird.Fly();         //自己的飞

    在我提供给你的这几个类当中,如果说你能抽象出一个父类,并且父类当中必须写上这几个子类共有的方法,然后你不知道如何去写这个方法,这个时候要用抽象类

    反之,抽象出来的父类可以写,还需要创建这个父类的对象,这个时候用虚方法,

    如果这几个类里面根本找不出父类,但是它们都有共同的行为,共同的能力,这个时候拿接口实现多态;

    比如鸟和飞机没有父类,但是它们都会飞,这个飞只能写成接口,不能写个父类去继承,因为根本提不出父类,

    //真的鸭子会游泳, 木头鸭子不会游泳,橡皮鸭子会游泳; 一看到会干什么,能干什么侧重于能力,能力就由接口来做,把真鸭子作为父类,但是不能在父类里面写游泳函数,因为木鸭子不会,不能写抽象方法,因为真的鸭子需要被创建 对象,真鸭子有意义,虚方法也不合适,因为木鸭子不会游泳,所以用接口最合适;

    public class RealDuck:ISwimming

    {  

        public void Swim()  

       {    

         Console.WriteLine("真的鸭子靠翅膀游泳");  

           }

    }

    public class MuDuck    

     {  

     }

    public class XPDuck:ISwimming    

    //不写方法体也不会报错,因为继承于RealDuck了,RealDuck里面有Swim了,但是由于他们游泳的方式不一样,因此没必要继承RealDuck

    {  

       public void Swim()  

       {   

        Console.WriteLine("橡皮鸭子漂着游泳");  

          }

    }

    public interface Iswimming

      {  

         void Swim();

      }

    ISwiming swim = new RealDuck()//new XPDuck() ;

    swim.Swim();

    超市收银管理系统,商品类,仓库类,超市类;

    类前面不加访问修饰符,默认是Internal表示同一个项目中可以访问;

    第一步,写商品的父类ProductFather;写价格,数量,编号三个自动属性;再写一个父类的构造函数

    GUID能够帮助我们产生全世界独一无二的编号,GUID是个结构, Guid.NewGuid().ToString();

    第二步,写商品的子类继承父类;写出每个子类的构造函数;

    第三部,收银系统中最重要的一个类,仓库类;

    存储货物;

    List<ProductFather>  list1 = new  List<ProductFather>(); //这样写表示把所有的商品都堆在一堆了,没有体现出分门别类存储商品;所有货物都混在一起,拿的时候不好拿;

    List<List<ProductFather>>  list2 = new  List<List<ProductFather>>();//在集合里面又放了一个集合;List<ProductFather>这个是数据的类型;

    在给list1添加数据的时候,可以把货物对象直接添加进来,坏处是取得时候很麻烦;取得时候不知道哪个下标是谁;看下标对应的是哪个对象;于是乎我们想到用两个集合;

    在给list2添加数据的时候只能添加一个集合进去;其实这个集合就是货架;给list2添加进去的不是商品,而是货架;

    不管是list1还是list2其实都是整个仓库;

    用list1存数据相当于 把商品直接扔进了仓库,在list2中添加进来的是数据的集合,仓库里的货架是货物的集合,所以往仓库添加数据的时候,先添加货架;

    List<ProductFather>  list1 = new  List<ProductFather>();

    list1[0] list1[1] list1[2]这些就是货物;//这种不好;

    List<List<ProductFather>>  list2 = new  List<List<ProductFather>>();//这段代码创建出了一个仓库;

    list2[0] list2[1] list2[2]这些就是货架;    

    因为创建仓库的时候已经要有货架了,因此我们要创建仓库类的构造函数;

    //list[0]存储宏基笔记本   list[1]存储三星手机   list[2]存储酱油   list[3]存储香蕉

    public CangKu()

    {  

       list.Add(new List<ProductFather>());  

       list.Add(new List<ProductFather>());  

       list.Add(new List<ProductFather>());  

       list.Add(new List<ProductFather>());  

    //如果要1000个对象,就要1000行,但是我们可以通过循环创建;

    }

    进货:

    public void JinPros(string strType,int count)

    {  

        for(int i = 0 ;i < count;i++)  

        {   

          switch(strType)    

          {        

             case "Acer":

            list[0].Add(new Acer(Guid.NewGuid().ToString(),1000,"宏基笔记本"));       

            break;    

           case "SangSung":

           list[1].Add(new SangSung(Guid.NewGuid().ToString(),2000,"三星手机"));      

           break;    

            case "JiangYou":

           list[2].Add(new JiangYou(Guid.NewGuid().ToString(),10,"老抽酱油"));    

           break;   

           case "Banana":

         list[2].Add(new Banana(Guid.NewGuid().ToString()20,"大香蕉"));     

           break;   

            }

       }

    }

    //来货之后,我们首先创建仓库对象,然后创建Getpros方法,往里面放货物;

    取货:

    public ProductFather[] QuPros(string strType,int count)

    {

        ProductFather[] pros = new ProductFather[conut];

         for(int i = 0;i < count; i++)

        {   

         switch(strType)    

         {      

           case:"Acer":      

          pros[i] = list[0][0];     

          list[0].RemoveAt[0];    

          break;       

         case:"SangSung":    

          pros[i] = list[1][0];      

          list[1].RemoveAt[0];   

          break;     

          case:"JiangYou":   

           pros[i] = list[2][0];     

          list[2].RemoveAt[0];    

           break;   

          case:"Banana":      

          pros[i] = list[3][0];      

          list[3].RemoveAt[0];     

          break;   

        }  

      }

        return pros;

    }

     List<List<ProductFather>>  list2 = new  List<List<ProductFather>>();//这种存储数据的方式是为了分类;

    展示货物,

    public void ShowPros()

    {  

       foreach(var item in list)

        {     

           Console.WriteLine(item[0].Name    item.count    item[0].Price);  

        }

    }

    泛型集合嵌套泛型集合的方法,我们以后会经常用到;

    List<List<ProductFather>>  list = new  List<List<ProductFather>>();

    list是仓库,我们给它添加的是List<ProductFather>货架;

    当创建仓库对象的时候,调用构造函数,我们给它创建货架;

    public  Cangku()

    {  

     List.Add(new List<ProductFather>());

     List.Add(new List<ProductFather>());

     List.Add(new List<ProductFather>());

     List.Add(new List<ProductFather>());

    }

    第四步 收银

    CangKu  ck = new CangKu();//创建仓库对象,会通过仓库的构造函数生成4个货架;但是货架上并没有货物,

    public SuperMarket()           //创建超市对象的时候,给超市的货架导入货物;

    {  

     ck.JinPros("Acer",1000);

     ck.JinPros("SangSung",1000);  

     ck.JinPros("JiangYou",1000);  

     ck.JinPros("Banana",1000);

    }

    跟用户交互的过程

    public void AskBuying()

    {   

      string strType = Console.ReadLine();   

      int count = Convert.Int32(Console.ReadLine());   

      //去仓库取货  

      Product[] pros = ck.Qupros(strType,count)  

      double realMoney = GetMoney(pros);  

     Console.WriteLine("选择打折方式 1-不打折 2-打九折 3-打八五折 4-买300送50 5-买500送100") //通过简单工厂的设计模式根据用户的输入获得一个打折对象;

     CalFather cal = GetCal(input);

     double totalMoney = cal.GetTotalMoney(realMoney);  

      }

    public double GetMoney(Product[] pros)

    {  

        double realMoney = 0;

        realMoney =  pro[0].price * pros.Length;    //之所以能这么写,是因为我们知道只有一种商品,如果不同种类,那就不能这么写了,  

    // for(int i = 0;i < pros.Length;i++)

    //  {  

    //    realMoney +=pros[i].Price

    //   }   

       return  realMoney;

    }

    //由于打折不固定,我们要提取出来一个打折的父类,打折的父类肯定有一个打折的方法,打折的父类不知道子类如何去打折,所以打折的父类只能提供一个抽象的打折方法,   所以要把父类写成一个抽象类,

    abstract  class CalFather

    {  

    public abstract double GetTotalMoney(double realMoney);

    }

    class CalNormal:CalFather        //正常情况下不打折

    {  

    public override double GetTotalMoney(double realMoney)  

    {   

      return realMoney;  

      }

    }

    class CalRate:CalFather       //按折扣率打折

    {   

       public double Rate   

      {    

          get;  

          set;  

       }

        public CalRate(double rate)   

      {    

         this.Rate = rate;  

        }

         public override double GetTotalMoney(double realMoney)  

      {   

           return realMoney * this.Rate;  

      }

    }

    class CalMN:CalFather

      {  

          public double M

          {     

             get;   

             set;  

          }

       public double N   

      {    

          get;    

          set;  

       }

    public CalMN(double m,double n)  

       {    

            this.M = m;    

            this.N = n;  

       }   

       public override double GetTotalMoney(double realMoney)  

       {      

           if(realMoney > this.M)    

         {        

               return RealMoney - this.N * (int)(realMoney/this.M);  

          }     

          else    

         {      

                return realMoney;    

          }   

       }

     }

    简单工厂设计模式,根据用户的输入返回对象; 根据用户的选择打折方式返回一个打折对象;

    public CalFather GetCal(string input)

    {  

       CalFather  cal = null;  

        switch(input)  

        {   

           case "1":

           cal = new CalNormal();   

           break;   

           case "2":

           cal = new CalRate(0.9);    

           break;   

           case "3":

           cal = new CalRate(0.85);   

           break;   

           case "4":

           cal = new CalMN(300,50);  

           break;

           case "5":

           cal = new CalMN(500,100);  

           break;  

        }  

        return cal;

    }

    因为展示货物的方法写在仓库类里面,如果在Main()函数里面只创建仓库对象的话,这个时候仓库只有货架,仓库没有货物,仓库只有在创建超市对象的时候才有货物, 因此在超市类里面写一个方法

    public void ShowPros()

    {   

       ck.ShowPros();//因此在Main函数中就不用创建仓库对象了,只要直接调用超市的ShowPros就可以了,

    }

    static void Main (string args[])

    {  

        //创建超市对象,   

        SuperMarkrt sm = new SuperMarkrt();  

        sm.ShowPros();

    }

    //扩展 现在只能买一样物品,把它改成买可以买多个物品;

    将密码输入数据库的时候,我们需要对数据库的密码进行加密,不能在数据库里明文保存;

    项目中只要涉及到存用户密码,就要给他MD5加密;

    把一个字符串转成MD5值这样一个过程,这就是MD5加密;我们就用代码来做;

    把字符串加密成MD5这样一个过程是不可逆的,就是说你只能把字符串变成MD5值,不能把MD5值变成字符串;

    简单一点的密码生成的MD5值可以解密过来,但是复杂一点的密码生成的MD5值就不能解密出来;

    MD5是一个抽象类,不能创建对象,但是我们可以通过它的Create静态方法模拟一个对象出来;并没有创建对象;

    public static string GetMD5(string str)

    {   

    MD5 md5 = MD5.Create(); //创建MD5对象;   

    //开始加密,将str转换成字符数组;   

    byte[] buffer = Encoding.Default.GetBytes(str);   

    //返回一个加密好的字节数组;   

    byte[] MD5Buffer = md5.ComputerHash(buffer);   

    //字节数组转字符串,理论上有三种,   

    //1.将字节数组中每个元素按照指定的编码格式解析成字符串; //pass掉就是我们写的,会产生乱码;   

    //2.直接将数组ToString();第二种pass因为转的是命名空间   

    //3.将字节数组中每个元素ToString();   

    //return Encoding.Default.GetString(MD5Buffer);   

    string strNew = "";   

    for(int i = 0 ; i < MD5Buffer.Length;i++)   

    {     

        strNew += MD5Buffer[i].ToString("x2");   

    }   

    return strNew; 

    //产生的是10进制的一串数字,但是MD5是16进制的;

    }

    .ToString("x");//在ToString()参数里面加个"x"就能把10进制转化为16进制;

    .ToString("x2");//在ToString()参数里面加个"x2"也能把10进制转化为16进制;x2就是使得16进制更整齐,有些地方的0给补起来了;

    .ToString();里面有很多参数,具有转格式的作用;

  • 相关阅读:
    最小二乘法拟合(python numpy) Littlefish
    我的话
    亿万富豪们给2013年毕业生的忠告
    网站色彩搭配<转载>
    灾难专用使你的网站变黑为雅安默哀
    <转载>协议森林13 9527 (DNS协议)
    不常见的HTML标签<转载>
    tomcat支持shml配置详解
    <转载>struts2 拦截器 interceptor
    乱码解决
  • 原文地址:https://www.cnblogs.com/hhsfrank/p/4231609.html
Copyright © 2011-2022 走看看