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 number | Design pattern name | Blog link | demo code link |
---|---|---|---|
1. | Factory design mode | https://blog.csdn.net/weixin_44993313/article/details/118046794 | https://github.com/Gaoning97/coding-life/tree/main/spring/src/main/java/com/raven/pattern/factory |
2. | Singleton design pattern | https://blog.csdn.net/weixin_44993313/article/details/118112188 | https://github.com/Gaoning97/coding-life/tree/main/spring/src/main/java/com/raven/pattern/singleton |
3. | Delegation mode & policy mode | https://blog.csdn.net/weixin_44993313/article/details/119301564 | https://github.com/Gaoning97/coding-life/tree/main/spring/src/main/java/com/raven/pattern/strategy |
4. | Template mode & adapter mode | https://blog.csdn.net/weixin_44993313/article/details/119301564 | https://github.com/Gaoning97/coding-life/tree/main/spring/src/main/java/com/raven/pattern/template |