设计模式学习总结(1)简单工厂模式、工厂方法模式、抽象工厂模式

设计模式学习

做了几个项目,发现设计模式的好处还是很多的,这东西就是只有你真正用到的时候才知道他的好处,否则学了也不知道所以然。所以设计模式学习我认为可以在先进行几个项目后,再来学习,这样学习的效果和感受才是最好的。

这次是做一个学习的笔记,内容还是主要以我看的两本书《大话设计模式》、《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)

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

1、工厂模式

简单工厂模式(simple Factory)

简单工厂模式不属于23种设计模式中的一种,简单工厂一般分为:普通简单工厂、多方法简单工厂、静态方法简单工厂。就是有一个专门生产某个产品的类

在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。

01普通

接口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

02多个方法

工厂类和测试类发生改变,其余不变

/**
 * @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();
    }
}

测试结果同上,就不放了。。。

03 多个静态方法

将工厂里的方法设置为静态的,这样在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();
    }
}

测试结果同上。。。

2、工厂方法模式(Factory Method)

简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。(给工厂也建立一个相应的接口,这样就好拓展了)

/**
 * @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();
    }
}

3、抽象工厂方法

工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。   
每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。   
每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品。   
    
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。   
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
工厂方法创建 "一种" 产品,他的着重点在于"怎么创建",也就是说如果你开发,你的大量代码很可能围绕着这种产品的构造,初始化这些细节上面。也因为如此,类似的产品之间有很多可以复用的特征,所以会和模版方法相随。 

抽象工厂需要创建一些列产品,着重点在于"创建哪些"产品上,也就是说,如果你开发,你的主要任务是划分不同差异的产品线,并且尽量保持每条产品线接口一致,从而可以从同一个抽象工厂继承。
对于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厂商这个父类中,增加生产耳麦的接口。最后在戴尔工厂,惠普工厂这两个类中,分别实现生产戴尔耳麦,惠普耳麦的功能。 以上。

猜你喜欢

转载自blog.csdn.net/anyue0205/article/details/82821003