设计模式的一些想法与总结(一)
依赖注入
首先需要解释一下什么是依赖注入(Dependency Injection),依赖注入据我的理解就是把在一个类中的属性的实例化不在内部实例化,而是在外部进行实例化。常见为把该类中属性的对象作为一个参数传入,然后赋值给该属性。目的是则是为了降低耦合性。要先了解这个是因为这个东东将会在设计模式中大规模应用。
具体代码如下:
public interface IPhone
{
void call();
}
public class iphone4:phone
{
void call()
{
//todo
}
}
public class People
{
IPhone myphone;
public void phone (IPhone _phone)
{
this.myphone=_phone;
}
public void call()
{
myphone.call();
}
}
上述可以描述的很简单,1:要建造的类:people 2:传入的参数:具体的手机对象,3:使用到的传入对象的属性或方法:call.我暂时杜撰此种翻译名称为DI2C( Dependency Injection TO CHINESE )描述。(反正四书五经都是杜撰的)。
设计模式原则与警句
- OO设计需要把握可复用,可扩展,可维护三个原则。
- 我们把系统中的会变化的部分抽出来封装
- 开放封闭原则:对修改封闭,对扩展开放。
- 多用组合,少用继承。
- 最少知识原则:只和你的密友谈话。
设计模式
本文只阐述思想,以及一种一对多映射的记忆方法,具体代码就不贴出了。
1 策略模式,
上述例子中是可以把iphone传入的,策略模式中,比如还是按照如上例子,还是写人这个类,则可以把人的具体的唱歌方式传入,如传入高音,低音等,把唱歌方式的对象作为一个参数传入。
用DI2C可以描述成
- 要声明的类 :策略使用者
- 传入的参数:具体的策略。
- 使用到的传入对象的属性或方法:传入策略的具体方法。
对本模式的感想就是要调用方法能不能直接委托传入啊。
2 观察者模式
也叫订阅模式,就是火警报警器发现着火了然后通知所有办公室的人逃出去这样,或者一家天气预报通知所有订了他们信息通知的人
这个模式也是用了依赖注入.首先是定义观察并通知信息的人的接口(有三个方法,register(),delete(),notify())和被通知信息的人的接口(因为可能有多个观察者)。然后定义一个观察者类和被观察者类分别继承上述两个接口。定义接口是为了规定该类必须实现的方法以及可以实现多态以实现依赖注入。观察者类中可以声明一个被观察List类用来管理被观察者。register()用来在list中增加被观察者,delete()能在list中去掉一个被观察者。而notify()则通知所有观察者。
观察者中的依赖注入:
- 首先要声明的类:观察者。
- 传入的参数:被观察者。
- 使用到的属性或方法:被观者的信息,比如手机号码用来发通知信息等等。
3 装饰模式
装饰模式就是不断在一个类中注入另一个类。比如一个人,套上T-shirt,套上裤子,套上外套,等等,都是在一个类中加上衣服类。由于需要套上之后还是一个人类。装饰模式中,不断将人那个类注入到衣服类中。所以装饰类就有必要也继承于人类。其实我在这里觉得这样很别扭,装饰类继承于人,那还叫装饰类吗,不是该叫装饰的人吗,人类含着人类那不叫怀孕吗。在我看来还不如直接在people类中建立一个衣服类的泛型,然后将一个一个衣服类add进去,展示的时候按顺序display出来。个人想法,欢迎大家一起讨论。
总结一下
- 首先要声明的类:被装饰者类
- 传入的参数:装饰品类(衣服,机器组件等等)
- 使用到的属性和方法:如游戏中展示人物,需要把衣服一件一件的展示出来,就需要用到每一件衣服的展示功能。
4 工厂模式
这里谈个问题。
这个模式开始我觉得很鸡肋。因为本来直接声明一个类,现在却先声明一个工厂然后通过工厂来声明一个实例。
原来的
IConcrete InstanceA=new ConcreteA();
IConcrete InstanceB=new ConcreteB();
现在要写成
IFactory factoryInstanceA=new FactoryA();
IConcreteA InstanceA=factoryInstanceA.CreateInstance();
IFactory factoryInstanceB=new FactoryB();
IConcreteA InstanceB=factoryInstanceB.CreateInstance();
不但原本好好的一句话搞定的事情变成了两句话,另外增加一个ConcreteB 类的同时要增加一个对应的工厂类。着实让我看不太懂。后来搜了一下说是为了封装实例创建过程。
“为什么要封装实例创建过程?”
上网搜了一下很难搜到,总结出来两点
- 类名很长或者实例化过程比较复杂的时候,那么就用工厂方法比较好。
- 这个类的创建过程以后很可能会发生变化。这个时候改变具体创建方法内部代码就不会影响客户端代码。
然后我就想,这个工厂方法还是在合适的时候用,不然只会越用越复杂。特别如果使用三层架构时,你能想象在Model层中每个类中再加一个相对应的工厂类生产专门的类吗。但是如果有需要的情况下还是能好的解耦的。我觉得小系统中是没必要用。大系统的话对维护要求比较高的情况下用用还是不错的。
就拿做pizza来说,今天创建可能是拿的是小作坊的手工制造,过几年小作坊变牛X了用的都是机器,或者披萨的原料变了,实例化的参数不一样了,这个时候改变参数就不会有修改客户端的问题。
5 单例模式
怎么做到让一个类不能被重复实例化呢。老婆什么的可不能到处实例化啊。
三步走,
1把该类的构造方法私有化,这样别人就不可以随便实例化啦。
2在类内部声明一个与该类同类型的对象指向null(私有静态)。(如private static LP A;)
3把第二部中的对象实例化这个过程放到内部的一个CreateInstance方法中调用,如果对象已经不为null,则实例化,否则直接直接返回。
怎么应对并发请搜索双重锁定在此不再多讲。
6 适配器模式
用过非国行的手机的人都知道,会有一个电压转换器,因为国内外的电压时不同的,所以就需要转换电压。而这个适配器模式就是充当类似电压转换器的作用。
首先这里也用到了依赖注入,
要声明的类:适配器类(继承想要转化成的类型接口,因为这里要遵循接口规范)
传入的参数:需要被转化的对象
使用到的属性或者方法:这里的方法是适配器自己定义的方法,调用注入对象的属性进行一些列转化算法之后输出。
适配器还分对象适配器和类适配器
7 外观模式
外观模式,把一些组件的功能组织起来一起调用。比如开机,开启windows,开启360,开启搜狗输入法,开启有道词典这一系列经常要用的软件可以开机启动,就需要这一系列动作放到一起去执行。只需要把windows,360,搜狗输入法等对象注入一个类,然后由这个类集中初始化就行了。
要声明的类:调用者客户端,如电脑,软件。
传入的参数:需要被集中调用的对象。
使用到的属性或方法:集中调用的方法。如电脑的开机方法等等。
外观模式让使用者更加方便,提供一键操作方式。
8 模板方法模式
模板方法模式定义一个操作的算法骨架,而将一些步骤延迟到子类中去实现,可以不改变一个算法的结构即可以重新定义概算法的某些特定步骤。就是定义一个抽象基类,里面的一些方法已经定义好,还有一些虚方法未继承,可以用子类按需要继承该基类然后实现里面没实现的方法。
首先个人觉得这个方法还是比较好用的。但是说白了也就是抽象类最基本的使用,如果抽象类用的多了自然就会这种模式了。这个模式只要会用abstract的都基本自然会用,没必要多看。
9 迭代器模式
迭代器模式我们用的不要太多,最简单的foreach就是用迭代器模式实现的。数据结构中我们知道,链表的遍历实现,while(P->next!=null) p=p.next。这一小段代码是用来遍历链表的。我觉得迭代器模式就很像。一个迭代器接口方法里面有三个主要方法,一个是利用依赖注入把要遍历的数组对象传入迭代器的。然后就是hasNext()方法和Next()方法。hasNext用来判断是否有有下一个,如果有则利用Next()方法返回下一个item,然后操作这个item()。这就是迭代器方法的本质。这个模式有了foreach之后基本就用不到了,了解即可。
10组合模式
组合模式不是很难。但是简单的东西都不好描述。组合模式讲述的是一个树形结构,一个根节点会有一些孩子节点,这些孩子节点可能是叶子节点(没有子节点),也可能是其他节点的父节点。我们把节点抽象成一个基类,所有的普通节点和父节点都将继承这个基类。这个基类有一些方法,比如可以添加孩子节点,去掉孩子节点,这样这个基类就需要add(),remove()方法,其他的方法可以依据具体信息而表现出来。他还需要一个泛型List管理他的的孩子节点。这样,树与树,节点与树,节点与节点都可以构成一棵树。而构成后的树,可以继续扩展开来。这就是组合模式,其实就是数据结构里的树形结构,如果你看不懂我说的这段,建议你看完源代码你就理解了。
因为一些原因,先写这么些部分,下次再继续写。
欢迎园友们来一起讨论,无论褒贬我都会虚心接受,您的支持是我的动力。