封装

封装特性为程序设计提供了系统与系统、模块与模块、类与类之间交互的实现手段。隐藏了内部的具体实现细节,对外提供了统一的访问接口,来操作内部数据成员。}

using System;

namespace ConsoleApp1
{
    public class ATM
    {
        //定义私有方法,隐藏具体实现
        private Client GetUser(string userID) { }
        private bool IsValidUser(Client user) { }
        private int GetHash(int money) { }

        //定义公有方法,提供对外接口
        public void CashProcess(string UserId, int money)
        {
            Client tempUser = GetUser(userID);
            if (IsValidUser(tempUser))
            {
                GetCash(money);
            }
            else
            {
                Console.WriteLine("你不是合法用户");
            }
        }
    }
    public class Client
    {

    }
    class Program
    {
       
        
        static void Main(string[] args)
        {
          
        }
    }
}

字段:通常定义为private,标识类的状态信息。CLR只支持只读和读写字段。只读地段只能在构造函数中被赋值。

public class Client
{
  private string name; 
  private int age;
  private string password;          
}

我们可以通过类的实例访问和改变字段内容。

 

public static void Main()
{
  Client xiaowang = new Client();
  xiaowang.name = "Xiao Wang"
  xiaowang.age = 27;
  xiaowang.password = "123456"    
}

同时小王的年龄不可能是1000

xiaowang.age = 1000

所以对字段公有化的操作,会破坏对象的状态信息,数据安全性和可靠性无法保证。

所以,封装的第一个原则就是将字段定义为private

但是我们对对象的状态信息的控制又该如何实现呢。我们既希望以另外的方式提供给类的外部访问或改变,同时期望实现对数据的访问,因此,加入了另外一个概念,属性。

属性(property)通常定义为public,表示对类的外部成员,属性具有可读、可写的属性,通过get或set访问器来实现读写控制。

 public class Client
    {
        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                name = value == null ? String.Empty : value;
            }
        }

        private int age;

        public int Age
        {
            get { return age; }
            set
            {
                if ((value>0 && value<150)) {
                    age = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("年龄信息不正确");
            //异常指定的信息超出了容量的范围 } } }

因此,属性的实质就是在编译时分别将get和set访问器实现为对外方法,从而达到控制属性的目的,对属性的读写行为伴随的实际是一个相应方法的调用。

因此,我们也可以定义自己的get和set访问器。

public string get_Password()
{
    return password;
}
public string set_Password(string value)
{
     if(value.Length<6){
     password = value;
}
}

这样的方式显然没有实现get和set访问器来得轻便,而且对属性的操作也带来多余的麻烦。下面的这种方式显然更加方便。

public string Password
{
    get {return passowrd;}
    set {
         if(value.Length<6){
              password = value;
    }
    }
}        

相应的属性只读只需要实现get,属性为只写,只需要实现set.

通过对公共属性的访问来实现对类状态信息的读写控制,1是避免了对数据安全的访问限制,保证了内部数据的可靠性,二是避免了类拓展或者修改所带来的连锁反应。

至于修改变量带来的连锁反应,表现在对类的状态信息的需求信息发生变化时,如何来减少代码重构的基础上实现最小的损失和最大的补救。如client的用户姓名由简单name标识,换成FirstName和secondName

来实现,如果不是属性封装了字段而带来的隐藏内部细节的特点,就要拼命地替换为xiaoWang.name来实现。

private string firstName;
private string secondName;

public string Name
{
    get { return firstName + secondName; }
}

方法封装了类的行为,提供了类的对外表现。用于将封装的内部细节以公有方法提供对外接口,从而实现与外部的交互和相应。

封装的意义:

  通过对字段、属性和方法在封装性上这一点的分析。

  (1)字段通常为private,属性通常为public.而方法在内部实现为private,对外实现为public.从而保证对内部数据的可靠性读写控制,保证了数据的安全性和可靠性。同时又提供了与外部接口的有效交互。

  (2)封装的意义不知类设计层面对字段、属性和方法的控制,更重要的是广义层面,一个系统或软件开发之后,从维护和升级的目的考虑,一定要保证对外几口部分的绝对稳定。不管系统内部的功能性实现如何多变,保证接口稳定一定是保证软件兼容、稳定、健壮的根本。

      因此,OO智慧中的封装性旨在保证:

  隐藏系统实现的细节,保证系统的安全性和可靠性。

  提供稳定不变的对外接口。因此,系统中相对稳定的部分常被抽象为接口。

  封装保证了代码模块化,提高了软件的服用和功能分离。

  

  封装的规则:

    尽可能调用类的访问器,而不是成员,即使实在类的内部。

              内部私有部分可以随意更改,但是一定要保证外部接口稳定的前提下。

    对字段的读写控制实现为属性,而不是方法。

posted @ 2021-11-29 18:56  马雪峰1  阅读(53)  评论(0编辑  收藏  举报