设计模式
29 Apr 20180 适配器模式
client -> adaptor interface -> adaptor class -> adaptee
不要为了适应功能的interface而去继承修改,实现的耦合重不可复用,应该用adaptor来转换interface。
concrete:具体的,凝固。
tabular:扁平的,列表的
1 工厂模式
客户端代码调用工厂类,让工厂类的内部方法逻辑选择判断该实例化哪个具体类。
- 简单工厂模式的最大优点是工厂类中包含的必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端,去除了与具体产品的依赖;
- 简单工厂模式是把创建对象的判断逻辑放到了工厂类的静态方法里面了,后续增加工厂功能的话,就需要改动里面的逻辑代码,不符合开闭原则。客户端代码的逻辑要上升到工厂类中去修改具体方法逻辑,这样太过耦合。
2 迪米特法则(松耦合)
- 类之间应该松耦合,耦合越弱,越有利于复用,处于弱耦合的类被修改,不会对有关系的类造成波及。
- 如果两类不必彼此直接通信,那这两个类就不应该发生直接的相互作用。如果一个类需要调用另一个类的某一个方法,可通过第三者转发该调用。
3 单一职责原则
在类的职责上多思考,发现职责并把那些职责相互分离。如果你能想到多于一个的动机去改变一个类,那这个类就具有多于一个的职责,就该考虑类的职责分离了;窗口只负责窗口的逻辑,算法类只负责算法的逻辑。不应该揉在一起。
4 开放-封闭原则
- 重构代码可以达到面对需求时,对程序的改动是通过新增代码进行的,而不是更改现有代码;
- 查明可能发生的变化需要的时间越长,创建正确的抽象就越困难(未抽象的部分应用到了太多地方,对其重构抽象分离就越困难);
- 开发人员应该对程序中呈现出频繁变化的部分做出抽象;
- 拒绝不该抽象的地方抽象;
- 对扩展开放,对更改封闭。多扩充少修改,变化发生时,就立即创建抽象来隔离发生的变化;
5 依赖倒转原则
- 高层模块不应该依赖底层模块,两个都应该依赖抽象;
- 对接口编程,不要对实现编程;
- 里氏代换原则:使用父类的地方替换为子类,程序的行为不会变化,子类的属性方法应该是父类的超集;
- 依赖倒转就是模块之间谁也不要依赖谁,全部通过约定的接口连接。
- 强内聚,松耦合:模块内部各成分关联程度尽可能高,模块间应该尽可能少依赖;
6 装饰模式
动态地给一个对象添加格外的职责,就增加功能来说,比生成子类更为灵活。
- 装饰类实现的装饰功能往往是特殊的,不是通用的,为了特殊,没必要改动通用的代码;
- 类中的装饰功能从类中搬移出去,简化原有的类。类的核心职责和装饰功能区分开,可以去除相关类中的重复装饰逻辑;
- 通过各种装饰类一层层地包装传递实例化的对象。
7 代理模式
代理类和主体类采用相同的接口,保存引用使得代理能访问到被代理实体。代理类的使用场合:
- 远程代理,使不同地址空间的对象提供局部代表,隐藏其来自不同地址空间的事实,看上去来自本地;
- 虚拟代理,对象创建开销太大,代理存放实例化需要过长时间的对象,适当的时候再逐步实例化;
- 安全代理,控制正式对象的访问权限;
- 只能指引,访问对象时附加一些内务处理。
8 工厂方法模式
对简单工厂进一步抽象推广。后续追加需求,只需扩展,不需要修改。具体做法是:
- 定义一个用于创建对象实例的接口,在其接口的子类中实现不同的实例的创建,然后在客户端代码中选择具体创建哪种实例;
- 这是一种对对象创建过程的封装(封装在接口的子类中,封装也就是后续不用改动逻辑代码),降低了客户程序与产品对象的耦合;
- 依赖倒转原则的体现,高层的类和底层的类都通过抽象的接口类连接;
- 简单工厂模式的最大优点是工厂类中包含的必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端,去除了与具体产品的依赖;
- 简单工厂模式是把创建对象的判断逻辑放到了工厂类的静态方法里面了,后续增加工厂功能的话,就需要改动里面的逻辑代码,不符合开闭原则。客户端代码的逻辑要上升到工厂类中去修改具体方法逻辑,这样太过耦合。
10 模板方法模式
- 继承的意义是为了子类的能使用通用的模板,所有重复的代码都应该上升到父类中去;
- 抽象类是自底而上抽象出来的,接口是自顶向下设计出来的。
C#面向对象特性
- 字段和属性:
- 一般字段通常是类内部私有,属性是公有的对字段的控制方法。
- 方法重载:
- 方法重载提供了创建多个同名方法的能力,但是这些方法需要使用不同的参数类型
- 多态:
- 简单来说就是可以重写父类的虚方法,然后在使用的时候需要声明改为父类:
Dad aKid = new Child();
- 抽象类:
- 不能实例化
- 抽象方法必须被自雷重写
- 只要类中有抽象方法,那么此类就必须定义为抽象类
- 应包含尽可能多的共同代码,拥有尽可能少的数据
- 子孙类回溯之前的所有祖宗类都应该是抽象类
- 事件和委托:
- 委托是一种对具体事件的检测,委托把 需要进一步发生的事件B 绑定到 当前类的指定事件A上,委托检测A的发生,然后触发B的发生。
-
关键字:
- virtual/abstract:父类中使用虚方法供子类override覆写。abstract在父类中没有具体实现,必须在子类中实现,而virtual在父子类中都有实现;
- static:?????
- public/private:???
- protected/private:protected是当前类和其派生类都可访问,private是只有当前类的代码可以访问该字段;
- public class/abstract class:???
- base/this:???
-
base
关键字主要用于两个地方:-
子类构造方法处内使用,可以显式调用一下父类的构造方法。子类若不显式的调用父类的构造函数时,编译器会自动调用父类的无参构造函数:
public class Father { public Father() { Console.WriteLine("im father."); } public Father(string name) { Console.WriteLine("im father:{0}", name); } } public class Chlid: Father { public Chlid() { Console.WriteLine("im son."); } public Chlid(string name):base(name) { Console.WriteLine("im son:{0}", name); } } static void main(string[] args) { string name = "jake"; Chlid c = new Chlid(name); //父类带参构造方法先用一次,再是子类的构造 // 采用无参数的构造方法会自动触发父类的无参构造 // 若是子类带参的方法去掉base,实例化也同样触发父类无参构造 //Chlid c = new Chlid(); }
-
第二种就是可以帮助子类调用父类上已被重写的方法:
public class Father { protected string name = "WuKong"; public virtual void ShowName() { Console.WriteLine("Father's name is {0}", name); } } public class Chlid: Father { protected string name = "WuFan"; public virtual void ShowName() { base.ShowName(); //显式执行父类抽象/虚方法! Console.WriteLine("Chlid's name is {0}", name); } }
-