做了几个项目,发现设计模式的好处还是很多的,这东西就是只有你真正用到的时候才知道他的好处,否则学了也不知道所以然。所以设计模式学习我认为可以在先进行几个项目后,再来学习,这样学习的效果和感受才是最好的。
这次是做一个学习的笔记,内容还是主要以我看的两本书《大话设计模式》、《head first 设计模式》,以及我在网上找到的一些内容为主,还有就是附带的一些自己的感悟(这些有可能是有问题的,还会再改,所以大家要是看一定要有分辨地去看)。主要还是觉得做一个学习的笔记可能会是我坚持下去的动力。
下面这是从菜鸟教程上面摘的,感觉不错就拿下来了,http://www.runoob.com/design-pattern/design-pattern-intro.html
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
这些设计模式特别关注对象之间的通信。
下面是设计模式的一张关系图
1、开闭原则(Open Close Principle)
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3、依赖倒转原则(Dependence Inversion Principle)
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
5、迪米特法则,又称最少知道原则(Demeter Principle)
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。
简单工厂模式不属于23种设计模式中的一种,简单工厂一般分为:普通简单工厂、多方法简单工厂、静态方法简单工厂。就是有一个专门生产某个产品的类
在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。
接口shape类
/**
* 简单工厂模式
* 创建一个接口
* shape类:实现接口
*/
public interface shape {
void draw();
}
接口实现实体类:Circle类、Rectangle
public class Circle implements shape{
@Override
public void draw(){
System.out.println("draw a circle");
}
}
/**
* 简单工厂模式
* 创建一个实现接口的实体类
* Rectangle画一个矩形
*/
public class Rectangle implements shape{
@Override
public void draw(){
System.out.println("draw a Rectangle");
}
}
工厂类
/**
* 简单工厂模式
* 创建一个工厂,生成基于给定信息的实体类的对象
* 2018/9/23 15:40
*/
public class ShapeFactory {
//使用一个getShape方法获取形状类型对象
public shape getShape(String shapeType){
if(shapeType == null){
System.out.println("please enter right word:");
}else if(shapeType.equals("circle")){
return new Circle();
}else if(shapeType.equals("rectangle")){
return new Rectangle();
}
return null;
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: SimpleFactoryPatternTest
* @Description: 简单工厂模式,用于进行测试
* @Author: xinyuan
* @CreateDate: 2018/9/23 15:48
*/
public class SimpleFactoryPatternTest {
public static void main(String[] args){
ShapeFactory shapeFactory = new ShapeFactory();
//获取Circle对象,并调用它的draw方法
shape shape1 = shapeFactory.getShape("circle");
shape1.draw();
//获取Rectangle对象,并调用它的draw方法
shape shape2 = shapeFactory.getShape("rectangle");
shape2.draw();
}
}
测试结果:
draw a circle
draw a Rectangle
Process finished with exit code 0
工厂类和测试类发生改变,其余不变
/**
* @ProjectName: Factory_Pattern
* @ClassName: ShapeFactory1
* @Description: 多个方法的简单工厂模式的工厂类
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:06
*/
public class ShapeFactory1 {
public shape drawCircle(){
return new Circle();
}
public shape drawRectangle(){
return new Rectangle();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: SimpleFactoryPatternTest1
* @Description: 多个方法的简单工厂模式,用于进行测试
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:10
*/
public class SimpleFactoryPatternTest1 {
public static void main(String[] args){
ShapeFactory1 shapeFactory1 = new ShapeFactory1();
//获取Circle对象,并调用它的draw方法
shape shape1 = shapeFactory1.drawCircle();
shape1.draw();
//获取Rectangle对象,并调用它的draw方法
shape shape2 = shapeFactory1.drawRectangle();
shape2.draw();
}
}
测试结果同上,就不放了。。。
将工厂里的方法设置为静态的,这样在main里就可以不建立实体直接调用。
/**
* @ProjectName: Factory_Pattern
* @ClassName: ShapeFactory2
* @Description: 多个静态方法的简单工厂模式的工厂类
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:17
*/
public class ShapeFactory2 {
public static shape drawCircle(){
return new Circle();
}
public static shape drawRectangle(){
return new Rectangle();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: SimpleFactoryPatternTest2
* @Description: 多个静态方法的简单工厂模式的测试类
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:19
*/
public class SimpleFactoryPatternTest2 {
public static void main(String[] args){
shape circle = ShapeFactory2.drawCircle();
circle.draw();
shape rectangle = ShapeFactory2.drawRectangle();
rectangle.draw();
}
}
测试结果同上。。。
简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。(给工厂也建立一个相应的接口,这样就好拓展了)
/**
* @ProjectName: Factory_Pattern
* @ClassName: ShapeFactory
* @Description: 工厂类的接口
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:43
*/
public interface ShapeFactory {
public shape drawShape();
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: DrawCircleFactory
* @Description: 工厂方法模式,工厂实体类
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:45
*/
public class DrawCircleFactory implements ShapeFactory{
@Override
public shape drawShape(){
return new Circle();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: DrawRectangleFactory
* @Description: 工厂方法模式,工厂实体类
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:46
*/
public class DrawRectangleFactory implements ShapeFactory{
public shape drawShape(){
return new Rectangle();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: FactoryPatternTest
* @Description: 工厂方法模式测试类
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:47
*/
public class FactoryPatternTest {
public static void main(String[] args){
ShapeFactory shapeFactory = new DrawCircleFactory();
shape circle = shapeFactory.drawShape();
circle.draw();
ShapeFactory shapeFactory1 = new DrawRectangleFactory();
shape rectangle = shapeFactory1.drawShape();
rectangle.draw();
}
}
工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品。
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
工厂方法创建 "一种" 产品,他的着重点在于"怎么创建",也就是说如果你开发,你的大量代码很可能围绕着这种产品的构造,初始化这些细节上面。也因为如此,类似的产品之间有很多可以复用的特征,所以会和模版方法相随。
抽象工厂需要创建一些列产品,着重点在于"创建哪些"产品上,也就是说,如果你开发,你的主要任务是划分不同差异的产品线,并且尽量保持每条产品线接口一致,从而可以从同一个抽象工厂继承。
对于java来说,你能见到的大部分抽象工厂模式都是这样的:
---它的里面是一堆工厂方法,每个工厂方法返回某种类型的对象。
比如说工厂可以生产鼠标和键盘。那么抽象工厂的实现类(它的某个具体子类)的对象都可以生产鼠标和键盘,但可能工厂A生产的是罗技的键盘和鼠标,工厂B是微软的。
这样A和B就是工厂,对应于抽象工厂;
每个工厂生产的鼠标和键盘就是产品,对应于工厂方法;
用了工厂方法模式,你替换生成键盘的工厂方法,就可以把键盘从罗技换到微软。但是用了抽象工厂模式,你只要换家工厂,就可以同时替换鼠标和键盘一套。如果你要的产品有几十个,当然用抽象工厂模式一次替换全部最方便(这个工厂会替你用相应的工厂方法)
所以说抽象工厂就像工厂,而工厂方法则像是工厂的一种产品生产线
/**
* @ProjectName: Factory_Pattern
* @ClassName: Color
* @Description: 抽象工厂模式
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:17
*/
public interface Color {
public void fill();
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: Red
* @Description: 抽象工厂模式,color接口的实体类
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:18
*/
public class Red implements Color{
@Override
public void fill(){
System.out.println("color is red");
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: Blue
* @Description: 抽象工厂模式,color接口的实体类
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:20
*/
public class Blue implements Color{
public void fill(){
System.out.println("color is blue");
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: DrawBlueFactory
* @Description: java类作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:30
*/
public class DrawBlueFactory implements ShapeFactory{
@Override
public shape drawShape(){
return null;
}
@Override
public Color drawColor(){
return new Blue();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: DrawRedFactory
* @Description: java类作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:25
*/
public class DrawRedFactory implements ShapeFactory{
@Override
public shape drawShape(){
return null;
}
@Override
public Color drawColor(){
return new Red();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: FactoryPatternTest
* @Description: 工厂方法模式测试类
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:47
*/
public class FactoryPatternTest {
public static void main(String[] args){
ShapeFactory shapeFactory = new DrawCircleFactory();
shape circle = shapeFactory.drawShape();
circle.draw();
ShapeFactory shapeFactory1 = new DrawRectangleFactory();
shape rectangle = shapeFactory1.drawShape();
rectangle.draw();
ShapeFactory shapeFactory2 = new DrawRedFactory();
Color red = shapeFactory2.drawColor();
red.fill();
ShapeFactory shapeFactory3 = new DrawBlueFactory();
Color blue = shapeFactory3.drawColor();
blue.fill();
}
}
下面的这些是从菜鸟教程上找的,感觉总结的挺好的,就拿下来看看,这样也好以后复习。
下面例子中鼠标,键盘,耳麦为产品,惠普,戴尔为工厂。
简单工厂模式不是 23 种里的一种,简而言之,就是有一个专门生产某个产品的类。
比如下图中的鼠标工厂,专业生产鼠标,给参数 0,生产戴尔鼠标,给参数 1,生产惠普鼠标。
工厂模式也就是鼠标工厂是个父类,有生产鼠标这个接口。
戴尔鼠标工厂,惠普鼠标工厂继承它,可以分别生产戴尔鼠标,惠普鼠标。
生产哪种鼠标不再由参数决定,而是创建鼠标工厂时,由戴尔鼠标工厂创建。
后续直接调用鼠标工厂.生产鼠标()即可
抽象工厂模式也就是不仅生产鼠标,同时生产键盘。
也就是 PC 厂商是个父类,有生产鼠标,生产键盘两个接口。
戴尔工厂,惠普工厂继承它,可以分别生产戴尔鼠标+戴尔键盘,和惠普鼠标+惠普键盘。
创建工厂时,由戴尔工厂创建。
后续工厂.生产鼠标()则生产戴尔鼠标,工厂.生产键盘()则生产戴尔键盘。
/**
* @ClassName: Mouse
* @Description: Mouse接口类
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:36
*/
public interface Mouse {
public void sayHi();
}
/**
* @ClassName: DellMouse
* @Description: java类作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:39
*/
public class DellMouse implements Mouse{
public void sayHi(){
System.out.println("produce DellMouse");
}
}
/**
* @ClassName: HpMouse
* @Description: mouse接口实体类
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:40
*/
public class HpMouse implements Mouse{
public void sayHi(){
System.out.println("produce HpMouse");
}
}
/**
* @ClassName: Keybo
* @Description: java类作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:42
*/
public interface Keybo {
public void sayHi();
}
/**
* @ClassName: DellKeybo
* @Description: java类作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:43
*/
public class DellKeybo implements Keybo{
public void sayHi(){
System.out.println("produce DellKeybo");
}
}
/**
* @ClassName: HpKeybo
* @Description: java类作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:44
*/
public class HpKeybo implements Keybo{
public void sayHi(){
System.out.println("produce HpKeybo");
}
}
/**
* @ClassName: PcFactory
* @Description: 工厂类接口
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:45
*/
public interface PcFactory {
public Mouse createMouse();
public Keybo createKeybo();
}
/**
* @ClassName: DellFactory
* @Description: java类作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:46
*/
public class DellFactory implements PcFactory{
@Override
public Mouse createMouse() {
return new DellMouse();
}
@Override
public Keybo createKeybo() {
return new DellKeybo();
}
}
/**
* @ClassName: HpFactory
* @Description: java类作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:48
*/
public class HpFactory implements PcFactory{
@Override
public Mouse createMouse() {
return new HpMouse();
}
@Override
public Keybo createKeybo() {
return new HpKeybo();
}
}
/**
* @ClassName: AbstractFactoryPatternTest1
* @Description: 测试类
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:50
*/
public class AbstractFactoryPatternTest1 {
public static void main(String[] args){
PcFactory pcFactory = new DellFactory();
Keybo keybo = pcFactory.createKeybo();
keybo.sayHi();
Mouse mouse = pcFactory.createMouse();
mouse.sayHi();
PcFactory pcFactory1 = new HpFactory();
Keybo keybo1 = pcFactory1.createKeybo();
keybo1.sayHi();
Mouse mouse1 = pcFactory1.createMouse();
mouse1.sayHi();
}
}
在抽象工厂模式中,假设我们需要增加一个工厂
假设我们增加华硕工厂,则我们需要增加华硕工厂,和戴尔工厂一样,继承 PC 厂商。
之后创建华硕鼠标,继承鼠标类。创建华硕键盘,继承键盘类即可。
在抽象工厂模式中,假设我们需要增加一个产品
假设我们增加耳麦这个产品,则首先我们需要增加耳麦这个父类,再加上戴尔耳麦,惠普耳麦这两个子类。
之后在PC厂商这个父类中,增加生产耳麦的接口。最后在戴尔工厂,惠普工厂这两个类中,分别实现生产戴尔耳麦,惠普耳麦的功能。 以上。