美文网首页
23种设计模式之工厂模式

23种设计模式之工厂模式

作者: 阿跳爱学习 | 来源:发表于2018-12-13 08:18 被阅读0次

    记录自己对工厂模式的理解,如有不对的地方,请大家多多包涵,帮忙指出。

    作用:实现了创建者和调用者的分离。

    本文主要分三类:
    1.简单工厂
    2.工厂方法
    3.抽象工厂

    简单工厂

    本人挺喜欢牛仔裤的,我就以牛仔裤做例子吧,先从没有工厂模式的情况下创建一条牛仔裤。
    先创建一个牛仔裤的接口Jeans

    public interface Jeans {
        void wear();
    }
    

    现在创建两个品牌的牛仔裤的实体类,实现Jeans接口

    import android.util.Log;
    
    /**
     * 这是JEE牛仔裤.
     */
    
    public class JeansJee implements Jeans {
        @Override
        public void wear() {
            Log.d("TAG", "JEE牛仔裤穿起来就是潮");
        }
    }
    
    import android.util.Log;
    
    /**
     *这是Levis牛仔裤
     */
    
    public class JeansLevis implements Jeans {
        @Override
        public void wear() {
            Log.d("TAG","李维斯牛仔裤穿起来就是经典");
        }
    }
    

    现在我们试试没有工厂模式的情况下调用

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    import com.hdc.test.simple.Jeans;
    import com.hdc.test.simple.JeansJee;
    import com.hdc.test.simple.JeansLevis;
    
    /**
     * 这是调用者
     */
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //调用JEE牛仔裤
            Jeans jee = new JeansJee();
            jee.wear();
    
            //调用Levis牛仔裤
            Jeans levis = new JeansLevis();
            levis.wear();
    
        }
    }
    
    image.png

    这样写也可以啊,为什么要使用工厂呢?比如我是调用者,我想要一条Levis牛仔裤和一条Jee牛仔裤,但是我得知道怎么创建Levis牛仔裤和Jee牛仔裤,是不是就得去和实体类打交道?才能创建出来穿上?拜托,我只是一个调用者,我才不想知道这些过程,我只知道裤子能穿,其他的我才懒得管,这下工厂是不是就有它的价值了?我只需要让工厂去帮我创建就好了,并且这种写法也已经违反了设计模式六大原则中的依赖倒置原则(要针对抽象编程,而不是针对实现细节编程),下面我们创建一个工厂,在有工厂的情况下是一个什么情景。

    首先我们先创建一个工厂:

    /**
     * 这是牛仔裤制造工厂
     * 简单工厂也称为静态工厂
     */
    
    public class JeansFactory {
    
        public static Jeans jee() {
            return new JeansJee();
        }
    
        public static Jeans levis() {
            return new JeansLevis();
        }
    }
    

    然后在有简单工厂模式的情况下调用

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    
    import com.hdc.test.simple.Jeans;
    import com.hdc.test.simple.JeansFactory;
    
    /**
     *这是调用者
     */
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    //        //没有工厂的情况下调用
    //        //调用JEE牛仔裤
    //        Jeans jee = new JeansJee();
    //        jee.wear();
    //
    //        //调用Levis牛仔裤
    //        Jeans levis = new JeansLevis();
    //        levis.wear();
            
            //有工厂的情况下调用
            //调用JEE牛仔裤
            Jeans jee = JeansFactory.jee();
            jee.wear();
            
            //调用Levis牛仔裤
            Jeans levis = JeansFactory.levis();
            levis.wear();
    
        }
    }
    
    image.png

    这样我们是不是不需要直接和实体类打交道了?把所有一切都交给工厂,只需要告诉工厂说我需要JEE或者Levis就行了,这就符合先前说的依赖倒置原则了,但是简单工厂还是有缺点,因为这违反了设计模式六大原则中的开闭原则(对于扩展是开放的,对于修改是关闭的),这点缺点如果不是开发JDK啊这些不是什么问题,所以一般项目用简单工厂还是比较多的,为了弥补这个缺陷,工厂方法就有存在的价值了,下面我们来看看工厂方法怎么做。

    工厂方法

    老样子,先把牛仔裤接口和实体类建出来,先建牛仔裤接口

    /**
     *这是一个牛仔裤接口
     *
     */
    
    public interface Jeans {
        void wear();
    }
    

    创建Jee牛仔裤实体类并实现Jeans接口

    import android.util.Log;
    
    /**
     * 这是JEE牛仔裤
     */
    
    public class JeansJee implements Jeans {
        @Override
        public void wear() {
            Log.d("TAG", "JEE牛仔裤穿起来就是潮");
        }
    }
    

    创建Levis牛仔裤实体类并实现Jeans接口

    import android.util.Log;
    
    /**
     *这是Levis牛仔裤
     */
    
    public class JeansLevis implements Jeans {
        @Override
        public void wear() {
            Log.d("TAG","李维斯牛仔裤穿起来就是经典");
        }
    }
    

    好了,现在牛仔裤接口和牛仔裤实体类都有了,现在开始建工厂,首先得先创建一个工厂接口,在里边定义一个牛仔裤品牌工厂的方法

    /**
     * 这是一个工厂接口
     */
    
    public interface JeansFactory {
        Jeans jeansBrandFactory();
    }
    

    创建JEE工厂,并实现JeansFactory 接口

    /**
     * 这是一个JEE工厂
     */
    
    public class JeeFactory implements JeansFactory {
        @Override
        public Jeans jeansBrandFactory() {
            return new JeansJee();
        }
    }
    

    再创建一个Levis工厂,,并实现JeansFactory 接口

    /**
     * 这是一个Levis工厂
     */
    
    public class LevisFactory  implements JeansFactory{
    
        @Override
        public Jeans jeansBrandFactory() {
            return new JeansLevis();
        }
    }
    

    现在所有的都创建完成了,在有工厂方法的情况下这样调用

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    
    import com.hdc.test.factorymethod.Jeans;
    import com.hdc.test.factorymethod.JeeFactory;
    import com.hdc.test.factorymethod.LevisFactory;
    
    /**
     *这是调用者
     */
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    //        //没有工厂的情况下调用
    //        //调用JEE牛仔裤
    //        Jeans jee = new JeansJee();
    //        jee.wear();
    //
    //        //调用Levis牛仔裤
    //        Jeans levis = new JeansLevis();
    //        levis.wear();
    
            //简单工厂的情况下调用
            //调用JEE牛仔裤
    //        Jeans jee = JeansFactory.jee();
    //        jee.wear();
    //
    //        //调用Levis牛仔裤
    //        Jeans levis = JeansFactory.levis();
    //        levis.wear();
    
            //工厂方法情况下调用
            //调用JEE牛仔裤
            Jeans jee = new JeeFactory().jeansBrandFactory();
            jee.wear();
    
            //调用Levis牛仔裤
            Jeans levis = new LevisFactory().jeansBrandFactory();
            levis.wear();
    
        }
    }
    
    image.png

    使用工厂方法的好处就在于符合了文章开头的开闭原则,如果我需要加一个G-STAR品牌的牛仔裤,我只需要直接加就行了,不需要修改原有代码,这样去加:
    先创建一个G-star实体类,并实现Jeans接口

    import android.util.Log;
    
    /**
     * 这是G-star牛仔裤
     */
    
    public class JeansGstar implements Jeans {
        @Override
        public void wear() {
            Log.d("TAG","G-STAR牛仔裤穿起来就是舒服");
        }
    }
    

    然后创建一个G-star工厂,并实现JeansFactory 接口

    /**
     * 这是一个G-star工厂
     */
    
    public class GstarFactory implements JeansFactory {
        @Override
        public Jeans jeansBrandFactory() {
            return new JeansGstar();
        }
    }
    

    这样就添加完成了,不需要修改原有代码,已经符合开闭原则(对于扩展是开放的,对于修改是关闭的),调用试试。

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    
    import com.hdc.test.factorymethod.GstarFactory;
    import com.hdc.test.factorymethod.Jeans;
    import com.hdc.test.factorymethod.JeeFactory;
    import com.hdc.test.factorymethod.LevisFactory;
    
    /**
     *这是调用者
     */
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    //        //没有工厂的情况下调用
    //        //调用JEE牛仔裤
    //        Jeans jee = new JeansJee();
    //        jee.wear();
    //
    //        //调用Levis牛仔裤
    //        Jeans levis = new JeansLevis();
    //        levis.wear();
    
            //简单工厂的情况下调用
            //调用JEE牛仔裤
    //        Jeans jee = JeansFactory.jee();
    //        jee.wear();
    //
    //        //调用Levis牛仔裤
    //        Jeans levis = JeansFactory.levis();
    //        levis.wear();
    
            //工厂方法情况下调用
            //调用JEE牛仔裤
            Jeans jee = new JeeFactory().jeansBrandFactory();
            jee.wear();
    
            //调用Levis牛仔裤
            Jeans levis = new LevisFactory().jeansBrandFactory();
            levis.wear();
    
            //调用新增品牌G-star牛仔裤
            Jeans gstar = new GstarFactory().jeansBrandFactory();
            gstar.wear();
    
        }
    }
    
    image.png

    是不是很简单?但是这种写法符合设计模式原则了,但是就真的好吗?它也是有弊端的,对比简单工厂来说,结构更复杂,因为它多出了很多的文件,造成冗余,对于其实两种模式都有自己的优点和缺点,开发时候还得按情况而定。

    现在有一种情况是这样的,一件牛仔裤,我需要私人定制怎么办?比如我需要高端的布料,但是纽扣和拉链我只需要低端的就好,或者我需要低端布料,高端纽扣拉链,像这种自由组合,怎么办?但是这个工厂只生产高端产品或者低端产品,我是不是还要找其他工厂去做我想要的?这就涉及三个模式中最复杂的抽象工厂了。

    抽象工厂

    前提:抽象工厂是新增产品族的,而简单工厂和工厂方法是直接新增产品的,打个比方,抽象工厂就是做牛仔裤的零件的,比如布料、纽扣、拉链就是牛仔裤这个产品的产品族,而简单工厂和工厂方法是直接做产品的,比如一条牛仔裤。这两种概念是不一样的,一定要清楚,因为他们之间的作用是完全不同的。

    首先,先创建一个布料接口

    /**
     * 这是一个布料接口
     */
    
    public interface Cloth {
        void quality();
    }
    

    创建一个高端布料类并实现Cloth 接口

    import android.util.Log;
    
    /**
     * 这是高端布料
     */
    
    public class HighEndCloth implements Cloth {
        @Override
        public void quality() {
            Log.d("TAG","高端布料质量好");
        }
    }
    

    创建一个低端布料类

    import android.util.Log;
    
    /**
     * 这是低端布料
     */
    
    public class LowCloth implements Cloth {
        @Override
        public void quality() {
            Log.d("TAG","低端布料质量差");
        }
    }
    

    其次,创建一个拉链接口

    /**
     * 这是一个拉链接口
     */
    
    public interface Zipper {
        void durability();
    }
    

    创建一个高端拉链实体类,并实现Zipper 接口

    import android.util.Log;
    
    /**
     * 这是高端拉链
     */
    
    public class HignEndZipper implements Zipper {
        @Override
        public void durability() {
            Log.d("TAG","高端拉链,很耐久!");
        }
    }
    

    创建一个低端拉链实体类,并实现Zipper 接口

    import android.util.Log;
    
    /**
     *这是低端拉链
     */
    
    public class LowZipper implements Zipper {
        @Override
        public void durability() {
            Log.d("TAG","低端拉链,不耐久");
        }
    }
    

    再次,我们创建一个纽扣接口

    /**
     * Created by Administrator on 2018/12/12.
     */
    
    public interface PantsBuckle {
        void pantsBuckleMaterial();
    }
    

    创建一个高端纽扣实体类,并实现PantsBuckle 接口

    import android.util.Log;
    
    /**
     * 这是高端纽扣
     */
    
    public class HighEndPantsBuckle implements PantsBuckle{
        @Override
        public void pantsBuckleMaterial() {
            Log.d("TAG","高端纽扣,镶钻的");
        }
    }
    

    创建一个低端纽扣实体类,并实现PantsBuckle 接口

    import android.util.Log;
    
    /**
     * 这是低端纽扣
     */
    
    public class LowPantsBuckle implements PantsBuckle {
        @Override
        public void pantsBuckleMaterial() {
            Log.d("TAG","低端纽扣,铜质的");
        }
    }
    

    这下布料,纽扣,拉链都有了,最后我们就要创建工厂,我们现在需求主要是两种类型,一种是高端,一种是低端,所以建立两个工厂,一个高端工厂,专门做高端产品的,一个是低端工厂,专门做低端产品的,所以得先有一个工厂接口。
    先创建一个牛仔裤工厂接口

    /**
     *这是一个牛仔裤工厂接口,工厂主要生产布料,拉链以及纽扣
     */
    
    public interface JeansFactory {
        Cloth createCloth();
        Zipper createZipper();
        PantsBuckle createPantsBuckle();
    }
    

    然后创建一个高端工厂,并实现JeansFactory接口

    
    /**
     * 这是一个高端工厂
     */
    
    public class HighEndFactory implements JeansFactory {
        @Override
        public Cloth createCloth() {
            return new HighEndCloth();
        }
    
        @Override
        public Zipper createZipper() {
            return new HighEndZipper();
        }
    
        @Override
        public PantsBuckle createPantsBuckle() {
            return new HighEndPantsBuckle();
        }
    }
    

    然后再创建一个低端工厂,并实现JeansFactory接口

    /**
     * 这是一个低端工厂
     */
    
    public class LowFactory implements JeansFactory {
        @Override
        public Cloth createCloth() {
            return new LowCloth();
        }
    
        @Override
        public Zipper createZipper() {
            return new LowZipper();
        }
    
        @Override
        public PantsBuckle createPantsBuckle() {
            return new LowPantsBuckle();
        }
    }
    

    现在产品族有了,工厂也有了,这时候调用者就可以找牛仔裤工厂(JeansFactory )定制自己所需要的产品了,比如高端的布料,低端的拉链和纽扣,可以这样调:

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    
    import com.hdc.test.abstractfactory.Cloth;
    import com.hdc.test.abstractfactory.HighEndFactory;
    import com.hdc.test.abstractfactory.JeansFactory;
    import com.hdc.test.abstractfactory.LowFactory;
    import com.hdc.test.abstractfactory.PantsBuckle;
    import com.hdc.test.abstractfactory.Zipper;
    
    /**
     *这是调用者
     */
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    //        //没有工厂的情况下调用
    //        //调用JEE牛仔裤
    //        Jeans jee = new JeansJee();
    //        jee.wear();
    //
    //        //调用Levis牛仔裤
    //        Jeans levis = new JeansLevis();
    //        levis.wear();
    
            //简单工厂的情况下调用
            //调用JEE牛仔裤
    //        Jeans jee = JeansFactory.jee();
    //        jee.wear();
    //
    //        //调用Levis牛仔裤
    //        Jeans levis = JeansFactory.levis();
    //        levis.wear();
    
            //工厂方法情况下调用
            //调用JEE牛仔裤
    //        Jeans jee = new JeeFactory().jeansBrandFactory();
    //        jee.wear();
    //
    //        //调用Levis牛仔裤
    //        Jeans levis = new LevisFactory().jeansBrandFactory();
    //        levis.wear();
    //
    //        //调用新增品牌G-star牛仔裤
    //        Jeans gstar = new GstarFactory().jeansBrandFactory();
    //        gstar.wear();
    
            //抽象工厂情况下调用(牛仔裤工厂,我需要一条牛仔裤,这条牛仔裤必须是高端的布料,低端的拉链和低端的纽扣)
            //牛仔裤工厂使用高端工厂生产出高端布料
            JeansFactory jeansFactory_c = new HighEndFactory();
            Cloth cloth = jeansFactory_c.createCloth();
            cloth.quality();
    
            //牛仔裤工厂使用低端工厂生产出低端拉链
            JeansFactory jeansFactory_z = new LowFactory();
            Zipper zipper = jeansFactory_z.createZipper();
            zipper.durability();
    
            //牛仔裤工厂使用低端工厂生产出低端纽扣
            JeansFactory jeansFactory_p = new LowFactory();
            PantsBuckle pantsBuckle = jeansFactory_p.createPantsBuckle();
            pantsBuckle.pantsBuckleMaterial();
        }
    }
    
    image.png

    总结:
    1.简单工厂(也称静态工厂):虽然不符合开闭原则,但实际应用最多的。
    2.工厂方法:虽然符合了开闭原则,但会造成冗余,文件太多。
    3.可以增加产品族,不可用增加产品。
    谢谢大家查阅,有不对的地方欢迎指出,感恩。

    相关文章

      网友评论

          本文标题:23种设计模式之工厂模式

          本文链接:https://www.haomeiwen.com/subject/snfehqtx.html