c#编程细节(二)面向对象加深

面向对象加深理解

  //**封装**:数据安全;内部修改保持稳定;提供重用性;分工合作,职责分明;
  //方便构建大型复杂的系统
  //**继承**:去掉重复代码;可以实现多态
 //侵入性很强的类关系 
 //**多态**:相同的变量 相同的操作,但是不同的实现
 //方法的重载  接口&实现  抽象类&实现  继承

虚方法&抽象方法的选择

虚方法:
1、virtual方法表示此方法可以被重写, 也就是说这个方法具有多态.父类中的方法是通用方法,可以在子类中重写以重新规定方法逻辑。
2、virtual方法可以直接使用,和普通方法一样。
3、不是必须重写的. 子类可以使用base.方法 的方式调用, 无论有没有在子类使用override去重写。
virtual关键字只是明确标示此方法可以被重写, 其实它和一般的方法没有什么区别
相应的
sealed关键字标示此方法不可以被重写
抽象方法:
1、抽象方法没有提供实现部分。
2、抽象方法只能在抽象类中声明。
3、抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化。

1,
IExtend extend = new iPhone(); //new IExtend();
extend.Video();//运行时多态
BasePhone phone = new iPhone();
extend.Video();//报错:原因就是编译器的检查,其实运行中是没问题的,但编译器只能通过识别左边
2,
为啥不直接iphone i = new phone()?
易后期修改维护,例如后面调用iphone的方法修改成调用huawei,如果参数是Baseiphone则无需改动,否则需要新建一个huawei方法
面向抽象:只能用抽象里面的东西,只能如此
如果有个性化操作,那就别用抽象了,因为没有意义,如果非要加上个性化的操作那就使用泛型
3,
怎么选择接口和抽象类
接口: 只能约束 多实现更灵活 can do(这个类能做什么)
抽象类: 可以完成通用实现 只能单继承 is a(这个类能做什么并且这个类是什么)
例如: 门: 材质1 猫眼3 门铃3 -----放在接口里
开门(2) 关门(2) 报警(3)----放在抽象里

//接口用的更多,因为接口更简单灵活 除非有些共有的需要继承
IBaseService–BaseService–UserService

什么时候用静态方法 什么时候用普通方法
能普通就普通,除非这个方法确定没有什么扩展,
只是工具类方法 可以静态

委托加深

委托:是一个类,继承自System.MulticastDelegate,里面内置了几个方法
public delegate void NoReturnNoPara(T t);//1,声明:
NoReturnNoPara method = new NoReturnNoPara(this.DoNothing);//2 委托的实例化
method.Invoke();或者method();//委托的调用(invoke是委托中的实例方法,执行传进来的函数)
为什么不直接调用,而把这个方法放在委托里面?
判断逻辑传递进来+实现共用逻辑,委托就像一个指向函数的指针
委托解耦,减少重复代码
使用方式举例:
1,数据库的连接等操作都是重复代码
public T ExcuteSql(string sql, Func<IDbCommand, T> func)
{
using (SqlConnection conn = new SqlConnection(""))
{
conn.Open();
//还可以扩展事务
IDbCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
return func(cmd);
}
}
2,trycatch也经常被重复使用
///
/// 通用的异常处理
///
/// 对应任何的逻辑
public static void SafeInvoke(Action act)
{
try
{
act.Invoke();
}
catch (Exception ex)//按异常类型区分处理
{
Console.WriteLine(ex.Message);
}
}

异步多线程:基于委托
WithReturnNoPara method = new WithReturnNoPara(this.GetSomething);
int iResult = method.Invoke();
iResult = method();
var result = method.BeginInvoke(null, null);//异步调用
method.EndInvoke(result);

多播委托
形成一个方法链
使用例子:一个方法或者类中需要依次执行方法,可能是同一个类的也可能不是,此时可放到一个多播委托,在这个方法或者类中执行这个方法
两种特殊的委托
Action 0到16个参数的 没有返回值 泛型委托
Func 0到16个参数的 带返回值 泛型委托
存在意义:很多委托长得一样,参数列表 返回值类型都一样,但是不能通用
//在不同的框架组件定义各种各样的相同委托,就是浪费 比如ThreadStart委托
//所以为了统一,就全部使用标准的Action Func
事件
事件的本质是多播委托,带event关键字的委托的实例,event可以限制变量被外部调用/直接赋值
//委托和事件的区别与联系?
//委托是一个类型,比如Student
//事件是委托类型的一个实例,更精彩的描述
使用例子:观察者模式

/// 事件:可以把一堆可变的动作/行为封装出去,交给第三方来指定
(这个实现特点也就表明了一定要将事件的发布者,订阅者,事件动作的注册分开来写)
/// 预定义一样,程序设计的时候,我们可以把程序分成两部分
/// 一部分是固定的,直接写死;还有不固定的地方,通过一个事件去开放接口,外部可以随意扩展动作
///
/// 框架:完成固定/通用部分,把可变部分留出扩展点,支持自定义

题目:多个方法里面重复对数据库的访问 想通过委托解耦,去掉重复代码

首先针对重复代码做一个能集成方法
private T ExcuteSql(string sql, Func<SqlCommand, T> func)
{
using (SqlConnection conn = new SqlConnection(StaticConstant.SqlServerConnString))
{
using (SqlCommand command = new SqlCommand(sql, conn))
{
conn.Open();
SqlTransaction sqlTransaction = conn.BeginTransaction();
try
{
command.Transaction = sqlTransaction;
//command.Parameters.AddRange(parameters);
T tResult = func.Invoke(command);
sqlTransaction.Commit();
return tResult;
//int iResult = command.ExecuteNonQuery();
//if (iResult == 0)
// throw new Exception(“Update数据不存在”);

                }
                catch (Exception ex)
                {
                    sqlTransaction.Rollback();
                    throw;
                }
            }
        }
    }

对于查询
public T Find(int id) where T : BaseModel
{
Type type = typeof(T);
//string columnString = string.Join(",", type.GetProperties().Select(p => $"[{p.GetColumnName()}]"));
//string sql = $“SELECT {columnString} FROM [{type.Name}] WHERE Id={id}”;
string sql = $"{TSqlHelper.FindSql}{id};";

此处的sql语句也为了避免重复进行了封装
static TSqlHelper()
        {
            Type type = typeof(T);
            string columnString = string.Join(",", type.GetProperties().Select(p => $"[{p.GetColumnName()}]"));
            FindSql = $"SELECT {columnString} FROM [{type.Name}] WHERE Id=";
            FindAllSql = $"SELECT {columnString} FROM [{type.Name}];";
        }
        T t = null;// (T)Activator.CreateInstance(type);
        Func<SqlCommand, T> func = new Func<SqlCommand, T>(command =>
        {
            SqlDataReader reader = command.ExecuteReader();
            List<T> list = this.ReaderToList<T>(reader);
            T tResult = list.FirstOrDefault();
            return tResult;
        });
        t = this.ExcuteSql<T>(sql, func);
        }
源程序逻辑对比
     //using (SqlConnection conn = new SqlConnection(StaticConstant.SqlServerConnString))
    //{
    //    SqlCommand command = new SqlCommand(sql, conn);
    //    conn.Open();
    //    SqlDataReader reader = command.ExecuteReader();
    //    List<T> list = this.ReaderToList<T>(reader);
    //    t = list.FirstOrDefault();
    //    //if (reader.Read())//表示有数据  开始读
    //    //{
    //    //    foreach (var prop in type.GetProperties())
    //    //    {
    //    //        prop.SetValue(t, reader[prop.Name] is DBNull ? null : reader[prop.Name]);
    //    //    }
    //    //}
    //}
发布了43 篇原创文章 · 获赞 8 · 访问量 3915

猜你喜欢

转载自blog.csdn.net/MaYang_/article/details/103748250
今日推荐