Advanced learning journey - design pattern (template pattern & Adapter pattern)

Posted by Hebbs on Sun, 02 Jan 2022 12:18:07 +0100

1. Course objectives

1. Learn to use the template mode to sort out the business scenarios of workflow standardization.

2. Solve the compatibility problem of code functions gracefully by learning the adaptation mode.

3. Understand the use of template mode in JDK source code and spring source code

2. Content positioning

1. Deeply understand the application scenarios of template mode and adapter mode

2. Positioning advanced courses

3. Template mode

3.1 definition of template mode

1. Template pattern, also known as template method pattern, defines the skeleton of an algorithm and allows subclasses to provide implementation for one or more steps.

2. Template method enables subclasses to redefine some steps of the algorithm without changing the algorithm structure.

3. It belongs to behavioral design mode

3.2 applicable scenarios of template mode

1. Implement the invariant part of an algorithm at one time, and leave the variable behavior to subclasses for implementation.

2. The common behaviors in each subclass are extracted and integrated into a common parent class to avoid code duplication

3.3 Demo case

1. Class cases

Course template specification abstract class

/**
 * @PackageName: com.raven.pattern.template.course
 * @ClassName: NetworkCourse
 * @Blame: raven
 * @Date: 2021-08-03 16:17
 * @Description: Online class case:
 * Define course template classes and standardize the steps of creating courses
 * The template method pattern uses abstract classes to specify the entire process
 */
public abstract class AbstractNetworkCourse {

    protected final void createCourse() {
        // 1. Release preview materials
        this.releasePreviewMaterials();
        // 2. Prepare PPT
        this.preparePPT();
        // 3. Online teaching
        this.onlineDelivery();
        // 4. Submit courseware
        this.postNote();

        // 5. Submit homework
        // Determine whether a job is required. It is specified when subclass inheritance. If a job is assigned, it is required to submit the job
        if (needHomework()) {
            this.submitJob();
        }
    }

    /**
     * Hook method to fine tune the process
     * @return
     */
    protected boolean needHomework() {
        return false;
    }

    /**
     * If you assign a job, you need to submit it. Whether there is a job or not is customized by the subclass
     */
    abstract void submitJob();

    /**
     * Subclasses cannot override overridden methods defined with final
     */
    final void postNote() {
        System.out.println("The teacher handed out the courseware~");
    }

    final void onlineDelivery() {
        System.out.println("Teachers teach online");
    }

    final void preparePPT() {
        System.out.println("The teacher is preparing PPT ah");
    }


    final void releasePreviewMaterials() {
        System.out.println("The teacher sent the preview materials~");
    }
}

Courses

public class GoCourse extends AbstractNetworkCourse {

    @Override
    void submitJob() {
        System.out.println("Go Language does not require homework");
    }
}

public class JavaCourse extends AbstractNetworkCourse {

    private boolean needHomeworkFlag;

    public JavaCourse(boolean needHomeworkFlag) {
        this.needHomeworkFlag = needHomeworkFlag;
    }

    /**
     * The process is fine tuned to determine whether to execute the logic of submitting the job by constructing parameters
     * @return
     */
    @Override
    public boolean needHomework() {
        return needHomeworkFlag;
    }

    @Override
    void submitJob() {
        System.out.println("If java If the teacher has assigned homework, I'll write it!");
    }
}

Main

public class CourseTest {

    public static void main(String[] args) {

        System.out.println("GO GO GO !");
        GoCourse goCourse = new GoCourse();
        goCourse.createCourse();

        System.out.println("==========================");
        System.out.println("JAVA JAVA JAVA !");
        JavaCourse javaCourse = new JavaCourse(true);
        javaCourse.createCourse();

        System.out.println("==========================");
        JavaCourse javaCourse2 = new JavaCourse(false);
        javaCourse2.createCourse();

    }
}

2.JDBC case

jdbc template specification interface

/**
 * @PackageName: com.raven.pattern.template.jdbc
 * @ClassName: RowMapper
 * @Blame: raven
 * @Date: 2021-08-03 20:44
 * @Description: ORM Mapping customized interfaces
 * Define a template specification, and all result mappings need to implement this interface
 */
public interface RowMapper<T> {
    /**
     * Canonical result mapping
     * @param rs
     * @param rowNum Number of rows of data
     * @return Mapping returned data
     * @throws Exception
     */
    T mapRow(ResultSet rs, int rowNum) throws Exception;
}

jdbcTemplate

public class JdbcTemplate {

    private DataSource dataSource;

    public JdbcTemplate(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /**
     * Return data list according to sql query
     * @param sql Query sql
     * @param rowMapper Data RowMapper mapping
     * @param values Query parameter list
     * @return Data list
     */
    protected List<?> executeQuery(String sql,RowMapper<?> rowMapper, Object[] values){

        try {
            // 1. Get database connection
            Connection conn = this.getConnection();

            // 2. Create statement set
            PreparedStatement pstm =  this.createPrepareStatement(sql,conn);

            // 3. Execute statement set
            ResultSet rs = this.executeQuery(pstm, values);

            // 4. Processing result set
           List<?> resultList =  this.parseResultSet(rs,rowMapper);

            // 5. Close the result set
            this.closeResultSet(rs);

            // 6. Close the statement set
            this.closePreparedStatement(pstm);

            // 7. Close the database connection
            this.closeConnection(conn);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    protected void closeConnection(Connection conn) throws Exception{
        // If it is a database connection pool, it is the number of connections returned. It is closed by default
        conn.close();
    }

    private void closePreparedStatement(PreparedStatement pstm) throws Exception{
        pstm.close();
    }

    private void closeResultSet(ResultSet rs) throws Exception{
        rs.close();
    }

    /**
     * Traverse the result set data, map the result set to the object, and process the result set
     * @param rs Result set
     * @param rowMapper Mapping method
     * @return Encapsulated result data
     * @throws Exception
     */
    private List<?> parseResultSet(ResultSet rs, RowMapper<?> rowMapper) throws Exception{
        ArrayList<Object> resultList = Lists.newArrayList();
        int rowNum = 1;
        while (rs.next()){
            resultList.add(rowMapper.mapRow(rs,rowNum++));
        }
        return resultList;
    }

    /**
     * Set the request parameters and execute the statement set
     * @param pstm
     * @param values
     * @return
     * @throws Exception
     */
    private ResultSet executeQuery(PreparedStatement pstm, Object[] values) throws Exception{
        // Traversal setting request parameters
        for (int i = 0; i < values.length; i++) {
            pstm.setObject(i,values[i]);
        }
        return pstm.executeQuery();
    }

    /**
     * Create statement set
     * @param sql
     * @param conn
     * @return
     * @throws Exception
     */
    private PreparedStatement createPrepareStatement(String sql, Connection conn) throws Exception{
        return conn.prepareStatement(sql);
    }

    /**
     * Get database connection
     * @return
     * @throws Exception
     */
    private Connection getConnection() throws Exception {
        return dataSource.getConnection();
    }
}

Service related

@Data
public class User {
    private String username;
    private String password;
    private int age;
    private String address;
}

@Repository
public class UserDao extends JdbcTemplate {

    public UserDao(DataSource dataSource) {
        super(dataSource);
    }

    public List<?> selectAll() {
        String sql = "select * from t_user";
        return super.executeQuery(sql, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int rowNum) throws Exception {
                User user = new User();
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setAge(rs.getInt("age"));
                user.setAddress(rs.getString("address"));
                return user;
            }
        }, null);
    }
}

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public List<User> selectAll(){
        List<?> list = userDao.selectAll();
        return (List<User>) list;
    }
}

3.4 template pattern application in source code

1. In JDK:

abstractList get method
httpservlet service method

2. In mybatis:

baseExcutor

3.5 advantages of template mode

1. Improve code reusability

2. Improve code expansibility

3. Comply with the opening and closing principle

3.6 disadvantages of template mode

1. Increase in the number of categories

2. It indirectly increases the complexity of system implementation

3. The inheritance relationship has its own shortcomings. If a new abstract method is added to the parent class, all subclasses must be changed.

4. Adapter mode

4.1 definition of adapter mode:

1. Adapter pattern refers to converting the interface of a class into another interface expected by the customer, so that classes with incompatible original interfaces can work together.

2. It belongs to structural design mode

4.2 applicable scenarios of adapter mode

1. For an existing class, its methods and requirements do not match (the method results are the same or similar).

2. The adapter mode is not the design mode considered in the software design stage. It is a solution when the functions are similar but the interfaces are different due to different products and manufacturers with the software maintenance.

4.3 Demo case

4.3. 1. Transformer case

main

public class PowerAdapterTest {
    public static void main(String[] args) {
        PowerAdapter powerAdapter = new PowerAdapter(new Ac220());
        int i = powerAdapter.output5V();
        System.out.println(i);
    }
}

adapter

/**
 * @PackageName: com.raven.pattern.adapter.poweradapter
 * @ClassName: AC220
 * @Blame: raven
 * @Date: 2021-08-04 9:50
 * @Description: 220 alternating current
 */
public class Ac220 {

    public int outputAc220V(){
        int output = 220;
        System.out.println("Output current" + output + "V");
        return output;
    }
}

/**
 * @PackageName: com.raven.pattern.adapter.poweradapter
 * @ClassName: Dc5
 * @Blame: raven
 * @Date: 2021-08-04 9:52
 * @Description: DC 5V converter interface
 */
public interface Dc5 {

    /**
     * Output 5V current
     * @return
     */
    int output5V();
}


/**
 * @PackageName: com.raven.pattern.adapter.poweradapter
 * @ClassName: PowerAdapter
 * @Blame: raven
 * @Date: 2021-08-04 9:53
 * @Description: The AC adapter realizes the interface and converts Ac220 to Ac5V
 */
public class PowerAdapter implements Dc5 {

    private Ac220 ac220;

    public PowerAdapter(Ac220 ac220) {
        this.ac220 = ac220;
    }

    @Override
    public int output5V() {
        int adapterIntput = ac220.outputAc220V();
        int adapterOutput = adapterIntput / 44;
        System.out.println("use PowerAdapter Adapter input AC" + adapterIntput  + "V,output AC" + adapterOutput + "V");
        return adapterOutput;
    }
}

4.3. 2. Login case

V1:

main

public class SigninForThirdServiceTest {

    public static void main(String[] args) {
        SigninForThirdService signinForThirdService = new SigninForThirdService();
        // Original login method
        signinForThirdService.login("username", "password");

        // Add other login methods through inheritance
        signinForThirdService.loginForPhone("18998986655", "8686");
        signinForThirdService.loginForQQ("asdasdwqeqw");
        signinForThirdService.loginForWechat("ssadasdasd");
    }
}

/**
 * @PackageName: com.raven.pattern.adapter.loginadapter.v1.service
 * @ClassName: SiginService
 * @Blame: raven
 * @Date: 2021-08-04 10:08
 * @Description: Simulated login registration interface
 */
public class SigninService {

    public MsgResult regist(String username,String password){
        return MsgResult.success();
    }


    public MsgResult login(String username,String password){
        return MsgResult.success();
    }
}

/**
 * @PackageName: com.raven.pattern.adapter.loginadapter.v1.service
 * @ClassName: SigninForThridService
 * @Blame: raven
 * @Date: 2021-08-04 10:23
 * @Description: System upgrade, add other login and registration methods
 * Traditional way: provide more services by inheriting the previous login and registration services
 */
public class SigninForThirdService extends SigninService {

    /**
     * New registration and login method, login through QQ
     *
     * @param openId
     * @return
     */
    public MsgResult loginForQQ(String openId) {
        // 1.openId is globally unique and can be regarded as a user name (Extended)
        // 2. The default password is QQ_EMPTY
        // 3. Registration (create a new user in the original system)
        // 4. Call the original login method
        return loginForRegist(openId, null);
    }

    public MsgResult loginForWechat(String openId) {
        return null;
    }

    public MsgResult loginForPhone(String phone, String code) {
        return null;
    }

    /**
     * Call the registration and login method of the parent class to complete the registration and login
     *
     * @param username
     * @param password
     * @return
     */
    private MsgResult loginForRegist(String username, String password) {
        super.regist(username, password);
        return super.login(username, password);
    }
}

V2:
main

/**
 * @PackageName: com.raven.pattern.adapter.loginadapter.v1.service
 * @ClassName: SiginService
 * @Blame: raven
 * @Date: 2021-08-04 10:08
 * @Description: Simulated login registration interface
 */
public class SigninService {

    public MsgResult regist(String username,String password){
        return MsgResult.success();
    }


    public MsgResult login(String username,String password){
        return MsgResult.success();
    }
}

/**
 * @PackageName: com.raven.pattern.adapter.loginadapter.v2
 * @ClassName: IPassportForThird
 * @Blame: raven
 * @Date: 2021-08-04 10:44
 * @Description: Define login interface specification
 */
public interface IPassportForThird {

    MsgResult loginForQQ(String openId);

    MsgResult loginForWechat(String openId);

    MsgResult loginForPhone(String phone,String code);

}

/**
 * @PackageName: com.raven.pattern.adapter.loginadapter.service.v2
 * @ClassName: PassportForThirdAdapter
 * @Blame: raven
 * @Date: 2021-08-04 10:51
 * @Description: Login authentication adapter
 * Inherit the original login mode and realize the newly defined login mode
 */
public class PassportForThirdAdapter extends SigninService implements IPassportForThird {


    /**
     * Verify the adapter and hand over the real implementation to the QQAdapter
     *
     * @param openId
     * @return
     */
    @Override
    public MsgResult loginForQQ(String openId) {
//        LoginAdapter adapter = new LoginForQQAdapter();
//        if (adapter.support(adapter)) {
//            return adapter.login(openId, adapter);
//        }
        return processLogin(openId, LoginForQQAdapter.class);
    }


    /**
     * Verify the adapter and hand over the real implementation to WechatAdapter
     *
     * @param openId
     * @return
     */
    @Override
    public MsgResult loginForWechat(String openId) {
//        LoginAdapter adapter = new LoginForWechatAdapter();
//        if (adapter.support(adapter)) {
//            return adapter.login(openId, adapter);
//        }
        return processLogin(openId, LoginForWechatAdapter.class);
    }

    /**
     * Verify the adapter and hand over the real implementation to the PhoneAdapter implementation
     *
     * @param phone
     * @param code
     * @return
     */
    @Override
    public MsgResult loginForPhone(String phone, String code) {
//        LoginAdapter adapter = new LoginForPhoneAdapter();
//        if (adapter.support(adapter)) {
//            return adapter.login(phone, adapter);
//        }
        return processLogin(phone, LoginForPhoneAdapter.class);
    }

    /**
     * Call the registration and login method of the parent class to complete the registration and login
     *
     * @param username
     * @param password
     * @return
     */
    private MsgResult loginForRegist(String username, String password) {
        super.regist(username, password);
        return super.login(username, password);
    }

    /**
     * Method abstraction
     *
     * @param key
     * @param clazz
     * @return
     */
    private MsgResult processLogin(String key, Class<? extends LoginAdapter> clazz) {
        try {
            LoginAdapter adapter = clazz.newInstance();
            if (adapter.support(adapter)) {
                return adapter.login(key, adapter);
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}


adpater

/**
 * @PackageName: com.raven.pattern.adapter.loginadapter.service.v2.adapter
 * @ClassName: LoginAdapter
 * @Blame: raven
 * @Date: 2021-08-04 10:52
 * @Description: This interface is optional in the adapter and should not be confused with the template mode
 * The template pattern must be an abstract class, and here is just an interface
 */
public interface LoginAdapter {

    /**
     * Is the adapter supported
     * @param adapter
     * @return
     */
    boolean support(Object adapter);

    /**
     * Sign in
     * @param id
     * @param adapter
     * @return
     */
    MsgResult login(String id ,Object adapter);
}

public class LoginForPhoneAdapter implements LoginAdapter {
    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForPhoneAdapter;
    }


    /**
     * Define the logic of login through mobile phone number
     * @param id
     * @param adapter
     * @return
     */
    @Override
    public MsgResult login(String id, Object adapter) {
        return null;
    }
}

public class LoginForQQAdapter implements LoginAdapter {
    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForQQAdapter;
    }

    /**
     * Define the logic of login through QQ number
     * @param id
     * @param adapter
     * @return
     */
    @Override
    public MsgResult login(String id, Object adapter) {
        return null;
    }
}

public class LoginForWechatAdapter implements LoginAdapter {
    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForWechatAdapter;
    }

    /**
     * Define the logic for logging in through Wechat
     * @param id
     * @param adapter
     * @return
     */
    @Override
    public MsgResult login(String id, Object adapter) {
        return null;
    }
}
Serial numberDesign pattern nameBlog linkdemo code link
1.Factory design modehttps://blog.csdn.net/weixin_44993313/article/details/118046794https://github.com/Gaoning97/coding-life/tree/main/spring/src/main/java/com/raven/pattern/factory
2.Singleton design patternhttps://blog.csdn.net/weixin_44993313/article/details/118112188https://github.com/Gaoning97/coding-life/tree/main/spring/src/main/java/com/raven/pattern/singleton
3.Delegation mode & policy modehttps://blog.csdn.net/weixin_44993313/article/details/119301564https://github.com/Gaoning97/coding-life/tree/main/spring/src/main/java/com/raven/pattern/strategy
4.Template mode & adapter modehttps://blog.csdn.net/weixin_44993313/article/details/119301564https://github.com/Gaoning97/coding-life/tree/main/spring/src/main/java/com/raven/pattern/template

Topics: Java Design Pattern