Large Java Advanced topics (iv) design pattern of the factory pattern

Foreword

The third lesson we begin the topic today, began to explain design patterns, this section describes: Understanding the origin of design patterns, introduce design patterns can help us solve those problems as well as the origin and history of the factory model of scenario analysis. This chapter reference books "Spring 5 core principles" in the first chapter Spring internal organs Heart (common design patterns in Spring) (no electronic gear, combined with its essence is my own understanding, word for word hand knock out).

Recalling the principles of software design

Speaking before the design mode, we must first understand the software design principles. Now begin by recalling the seven principles of software design:
the opening and closing principles : open for extension, but closed for modification.
Dependency Inversion Principle : The abstract of the respective class or module does not affect each other, loose coupling.
Single Responsibility Principle : a class, interfaces, methods, only one thing.
Interface Segregation Principle : try to ensure the purity of the interface, the client should not rely unwanted interfaces.
Demeter : also known as the principle of least know, know, the better a class depends on its class.
Richter Substitution Principle : subclass can extend the functionality of the parent class but can not change the parent class of the original function.
Synthesis multiplexing principle : try object composition, polymerization, without using object inheritance relations to code reuse.

Why start from the design pattern

Although we usually write code to meet the needs but often not conducive to the development and maintenance of the project, through the rational use of design patterns, can make us easier to maintain in the future, so learn the reconstruction of the code is very important. Spring in the use of design patterns can be described most vividly, such as:
factory pattern: BeanFactory
Decorator: BeanWrapper
proxy mode: AopProxy
delegated mode: DispatcherServlet
Strategy Mode: HandlerMapping
adapter mode: HandlerAdapter
template mode: JdbcTemplate
observed by mode: ContextLoaderListener

It requires special statement that the design patterns has never been a single design patterns used independently. In practical applications, usually more mixed use design patterns, you have me, I have you.

Factory mode Detailed

Simple factory pattern

Simple factory pattern (Simple Factory Pattern) is determined by a factory object refers to creating an instance of which product class, but it does not belong GOF, 23 kinds of design patterns. Simple factory class facility suitable for small objects responsible for creating the scene, and the client only need to pass parameters corresponding to the factory on the production of the corresponding object, how to create objects of logic the caller does not need to be concerned about.

We grow fruit, for example, to create planting fruit Interface IFruit:

public interface IFruit {
    /**
     * 种植水果方法
     */
    void plant();
}
//实现种植苹果
public class Apple implements IFruit {
    public void plant() {
        System.out.println("种植苹果");
    }
}
//实现种植橙子
public class Orange implements IFruit {
    public void plant() {
        System.out.println("种植橙子");
    }
}

We look at the caller code when you want a certain kind of fruit planting time:

public static void main(String[] args) {
    //种植苹果
    IFruit fruit = new Apple();
    fruit.plant();
}

If you have to replace the cultivation of oranges at this time:

public static void main(String[] args) {
    //IFruit fruit = new Apple();    
    //种植橙子
    IFruit fruit = new Orange();
    fruit.plant();
}

Parent IFruit point to a subclass reference to Apple, the caller code needs to rely Aplle, such as planting fruit business more and more, the caller code will become more and more bloated. We find a way to decrease this dependence, to create details hidden. Although the code, the object we created is not complicated, but difficult to expand a code from the design point of view. We optimize the code with a simple plant.

Creating PlantFruitsFactory factory:

public static class PlantFruitsFactory {
    public IFruit PlantFruit(String fruitName) {
        //这里使用的if判断,用switch一样的道理
        if ("Apple".equals(fruitName)){
            return new Apple();
        }else if ("Orange".equals(fruitName)){
            return new Orange();
        }else {
            return null;
        }
    }
}

Modify the caller Code:

public class DemoTest {
    public static void main(String[] args) {
        IFruit fruit = PlantFruitsFactory.PlantFruit("Apple");
        fruit.plant();
    }
}

Let's look at the class diagram:

The caller no longer directly concerned with the details of creating, specify only need to pass parameters to the factory, the factory is responsible for creating an object corresponding to the caller. Although the basic realization of the logic of the factory model, but if With the expansion of the business, you need to create planting more varieties of fruits, plants always need to follow to modify the method does not comply with the principle of opening and closing. So we can re-optimization at the factory class:

public class PlantFruitsFactory {
    //包路径的前缀
    private static final String PACKAGE_PATH = "com.study.demo.";
    public static IFruit PlantFruit(String fruitName){
        try {
            return (IFruit) Class.forName(PACKAGE_PATH+fruitName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

So even if there is a new fruit varieties to add new requirements, we do not need to modify the code factory class, and only need to create a corresponding class factory creates an object corresponding to the caller of the reflection. (In fact, here you can also optimize the parameters of the method can be changed corresponding Class object, so you do not need a strong turn here do not demonstrate.)

Simple factory pattern in JDK source is everywhere, we now give you an example, such as the Calendar class, see
Calendar.getInstance () method, the following is an open concrete to create a class of Calendar:

//源码中的方法
private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale) {

        CalendarProvider provider =
                LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                        .getCalendarProvider();
        if (provider != null) {
            try {
                return provider.getInstance(zone, aLocale);
            } catch (IllegalArgumentException iae) {
                // fall back to the default instantiation
            }
        }
        Calendar cal = null;
        if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                    case "buddhist":
                        cal = new BuddhistCalendar(zone, aLocale);
                        break;
                    case "japanese":
                        cal = new JapaneseImperialCalendar(zone, aLocale);
                        break;
                    case "gregory":
                        cal = new GregorianCalendar(zone, aLocale);
                        break;
                }
            }
        }
        if (cal == null) {
            // If no known calendar type is explicitly specified,
            // perform the traditional way to create a Calendar:
            // create a BuddhistCalendar for th_TH locale,
            // a JapaneseImperialCalendar for ja_JP_JP locale, or
            // a GregorianCalendar for any other locales.
            // NOTE: The language, country and variant strings are interned.
            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                cal = new BuddhistCalendar(zone, aLocale);
            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                    && aLocale.getCountry() == "JP") {
                cal = new JapaneseImperialCalendar(zone, aLocale);
            } else {
                cal = new GregorianCalendar(zone, aLocale);
            }
        }
        return cal;
    }

Of course, the factory model also has his faults: Responsibilities factory class is relatively heavy and difficult to expand overly complex product structures.

Factory Method pattern

Factory Method pattern (FatoryMethod Pattern) refers to the definition of a created object's interface, but let the class that implements this interface to determine which instances of the class, so that the factory method to instantiate the class into subclasses were postponed. In the Factory Method pattern in users only need to be concerned about the desired product corresponding to the plant, without concern for the details of creating and adding new products in line with the principle of opening and closing.
Factory method pattern to solve the main problem of product extensions, in a simple factory, with the rich product chain, if you create a logical course of each are different, then the responsibility will become more and more factories, a bit like a universal factory, not easy to maintain. According to the principle of single responsibility we will continue to split the functions, specializing in hand dry. Apple factory created by Apple, Orange created by the Orange factory, the factory also made itself an abstract. Look at the code, create IFruitFactory Interface:

//工厂接口
public interface IFruitFactory {
    IFruit create();
}
//生成苹果的工厂
public class AppleFactory implements IFruitFactory {
    @Override
    public IFruit create() {
        return new Apple();
    }
}
//生成橙子的工厂
public class OrangeFactory implements IFruitFactory {
    @Override
    public IFruit create() {
        return new Orange();
    }
}
//调用方代码
public class DemoTest {
    public static void main(String[] args) {
        //创建苹果工厂 生产苹果
        IFruitFactory fruitFactory = new AppleFactory();
        fruitFactory.create().plant();
        //创建橙子工厂 生成橙子
        IFruitFactory orangeFactory = new OrangeFactory();
        orangeFactory.create().plant();
    }
}

Now we look at the class diagram:

Factory method applies to the following scenarios:
1, create an object requires a lot of repetitive code.
2, the client (application layer) does not depend on how the product class instance is created, the details of realization.
3, a class to specify which object created by its subclasses.
Factory method also has disadvantages:
1, the number of class too readily, increasing the complexity.
2, increasing the system's abstract and difficult to understand.

Abstract factory pattern

Abstract Factory (Abastract Factory Pattern) provide a means to create a product family of related or dependent product hierarchy a hierarchy object interface products, without specifying their concrete classes. The client (application layer) does not depend on how the product class instance is created, realized and other details, the emphasis is to create objects to use requires a lot of repetitive code with a series of related product objects (belonging to the same product family). Need to provide a product class library, all of the products appear in the same interface, so that the client does not depend on the specific implementation.

Or fruit, for example, now not only fruit plant grown fruit also began processing fruit. Equivalent to the current business change function for the same class is not simply just a fruit grown fruit. Processed fruits in two additional interfaces IPlant grow fruit and IProcess.

public interface IPlant {
    //种植产品
    void plant();
}
public interface IProcess {
    //加工产品
    void process();
}

Then create an abstract factory FruitFactory:

/**
 * 抽象工厂是用户的主入口
 * 在 Spring 中应用得最为广泛的一种设计模式
 * 易于扩展
 */
public interface FruitFactory {
    IPlant createPlant();

    IProcess createProcess();
}

Then create Apple product line:

//种植苹果
public class ApplePlant implements IPlant {
    @Override
    public void plant() {
        System.out.println("种植苹果");
    }
}
//加工苹果
public class AppleProcess implements IProcess {
    @Override
    public void process() {
        System.out.println("加工苹果");
    }
}

Creating Apple factory:

public class AppleFactory implements FruitFactory {

    @Override
    public IPlant createPlant() {
        return new ApplePlant();
    }

    @Override
    public IProcess createProcess() {
        return new AppleProcess();
    }
}

Corresponding oranges is the same.

The above code complete description of the product family two apples and oranges, but also describes the two product grades cultivation and processing. Abstract Factory perfectly clear layer of complexity to describe the relationship. However, we do not know we have not found, if we continue to expand the product level, will also join the sale Sale of products, so our code from the abstract factory, the plant-specific adjustment to all, it is clearly inconsistent with the principle of opening and closing. Therefore, the abstract factory is flawed:
1, provides for the expansion of new products all the difficulties collection of products, product family can be created, it is necessary to modify the interface of the abstract factory.
2, increasing the system's abstract and difficult to understand.

to sum up

Three ways the factory model, there is no absolute good or bad, appropriate scene mode appropriate to use, practical application, we must not be guilty of obsessive-compulsive disorder and even got a little older. In the actual needs of the hierarchical structure of the product upgrade is a very normal thing. We can according to the actual situation, if not frequent upgrades, you can not follow the principle of opening and closing. Code upgrade every six months or once a year, then why not upgrade it?

Guess you like

Origin www.cnblogs.com/whgk/p/12508859.html