23种设计模式在Android中的应用
所有江湖偶遇,都是宿命相逢 ----《逆水寒》,只是觉得文案不错,就用了。哈哈!
一.设计原则:
单一职责原则(SRP):任何一个对象都应给只有一个单独的职责(“低耦合,高内聚”)
里氏替换原则(LSP):在任何父类出现的地方都可以用子类替换
依赖注入原则(DIP):要依赖于抽象而不是依赖于具体实现(此原则是开闭原则的基础)
接口分离原则(ISP):不应该强迫他们的客户程序依赖他们不需要的方法
迪米特原则(LOD):一个对象应该对其他对象尽可能少的了解,意思就是降低各个对象之间的耦合。
开闭原则(OCP):一个对对象对扩展是开放的,对修改是关闭的。
二.23中设计模式
1.工厂模式(Factory Pattern):在工厂模式中,客户类与工厂来是分开的,消费者任何时候需要产品只需要向工厂请求就好,消费者无需修改就可以接纳新产品。缺点是:当前产品修改是工厂也需要修改。
2.建造模式(Builder Pattern):将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同表象的产品,建造模式使得产品内部表象可以独立的变化,客户不必知道产品的内部细节。建造模式可以强制实行一种分步骤的建造过程。
AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("") .setIcon(R.drawable.ic_launcher_foreground) .setView(R.layout.activity_main) .setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey(DialogInterface dialogInterface, int i, KeyEvent keyEvent) { return false; } }) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialogInterface) { } }) .create().show();
3.工厂方法模式(Abstract Factory Pattern):在工厂方法模式中,核心工厂类不再负责所有的产品的创建,而是将具体创建工作交给子类处理,成为一个抽象角色,仅负责给出具体工厂必须实现的接口,而不接触某款产品的实例化细节。
4.原型模型模式(Prototype Pattern):原型模型是通过给定一个原型对象来指明要创建的的对象类型,可以用复制这个对象的方法创建更多的对象,原型模型允许动态的增加或减少产品类。缺点是:每一个类必须配备一个克隆方法。
5.单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。
- 饿汉式单例
-懒汉式单例
饿汉模式是在系统运行起来,在装在类的时候就进行初始化的操作,外部对象使用的时候不需要做任何判断可以直接使用,从效率上来说是优于懒汉模式的.但是对比懒汉模式的延迟加载技术,不管系统用不用该实例,内存都会在最开始的时候创建出来.跟懒汉的时间换空间正好相反,饿汉是空间换时间。
6.适配器模式(Adapter Pattern):把我一个类的接口变化成客户端期望的另一个接口。
Adapter.java Android8.0源码
/** * adapter 对象充当 AdapterView 和该View展现数据的桥梁。提供对数据的访问。 * 还负责每一个 android.view.View 控件的数据集控制。 * @see android.widget.ArrayAdapter * @see android.widget.CursorAdapter * @see android.widget.SimpleCursorAdapter */ public interface Adapter { /** * Register an observer that is called when changes happen to the data used by this adapter. * 当这个适配器使用的数据放生变化时候,注册一个观察者 * @param observer the object that gets notified when the data set changes. * @param observer 当数据集发生变化,得到通知的对象 */ void registerDataSetObserver(DataSetObserver observer); /** * Unregister an observer that has previously been registered with this * adapter via {@link #registerDataSetObserver}. * 该方法是注销观察者作用, * @param observer the object to unregister. * @param observer 需要注销的观察者 */ void unregisterDataSetObserver(DataSetObserver observer); /** * How many items are in the data set represented by this Adapter. * adapter数据集大小 * @return Count of items. * @return 返回数据集大小 */ int getCount(); /** * Get the data item associated with the specified position in the data set. * 返回数据集对应索引(position)的数据项对象 * @param position Position of the item whose data we want within the adapter's * data set. * @return The data at the specified position. */ Object getItem(int position); /** * Get the row id associated with the specified position in the list. * 返回数据集对应索引(position)的数据项Id * @param position The position of the item within the adapter's data set whose row id we want. * @return The id of the item at the specified position. */ long getItemId(int position); /** * Indicates whether the item ids are stable across changes to the * underlying data. * 如果相同的ID总是引用相同的对象,则为true。 * @return True if the same id always refers to the same object. */ boolean hasStableIds(); /** * Get a View that displays the data at the specified position in the data set. You can either * create a View manually or inflate it from an XML layout file. When the View is inflated, the * parent View (GridView, ListView...) will apply default layout parameters unless you use * {@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)} * to specify a root view and to prevent attachment to the root. * 返回数据集中对应索引(position)指定的View。同样也可以创建一个视图或者通过xml布局inflate。 * 如果是通过inflate获取视图时候,@param parent 可以是GridView 或者ListView等控件。 * 除非你用{@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)}指定根视图并防止附着,否则使用默认的布局参数。 * @param position The position of the item within the adapter's data set of the item whose view * we want. * @param position 我们想要返回的视图,对应数据集索引(position) * @param convertView The old view to reuse, if possible. Note: You should check that this view * is non-null and of an appropriate type before using. If it is not possible to convert * this view to display the correct data, this method can create a new view. * Heterogeneous lists can specify their number of view types, so that this View is * always of the right type (see {@link #getViewTypeCount()} and * {@link #getItemViewType(int)}). * @param convertView 如果可以,重用旧视图。注意:需要检查视图不是null并且是适当的类型。如果不能重用,可以创建一个视图。 * @param parent The parent that this view will eventually be attached to * @param parent 根视图 * @return A View corresponding to the data at the specified position. * 返回呈现数据集索引对应数据项的视图。 */ View getView(int position, View convertView, ViewGroup parent); /** * An item view type that causes the {@link AdapterView} to ignore the item * view. For example, this can be used if the client does not want a * particular view to be given for conversion in * {@link #getView(int, View, ViewGroup)}. * * @see #getItemViewType(int) * @see #getViewTypeCount() */ static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE; /** * Get the type of View that will be created by {@link #getView} for the specified item. * * @param position The position of the item within the adapter's data set whose view type we * want. * @return An integer representing the type of View. Two views should share the same type if one * can be converted to the other in {@link #getView}. Note: Integers must be in the * range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can * also be returned. * @see #IGNORE_ITEM_VIEW_TYPE */ int getItemViewType(int position); /** * <p> * Returns the number of types of Views that will be created by * {@link #getView}. Each type represents a set of views that can be * converted in {@link #getView}. If the adapter always returns the same * type of View for all items, this method should return 1. * </p> * <p> * This method will only be called when the adapter is set on the {@link AdapterView}. * </p> * * @return The number of types of Views that will be created by this adapter */ int getViewTypeCount(); static final int NO_SELECTION = Integer.MIN_VALUE; /** * @return true if this adapter doesn't contain any data. This is used to determine * whether the empty view should be displayed. A typical implementation will return * getCount() == 0 but since getCount() includes the headers and footers, specialized * adapters might want a different behavior. */ boolean isEmpty(); /** * Gets a string representation of the adapter data that can help * {@link android.service.autofill.AutofillService} autofill the view backed by the adapter. * * <p> * It should only be set (i.e., non-{@code null} if the values do not represent PII * (Personally Identifiable Information - sensitive data such as email addresses, * credit card numbers, passwords, etc...). For * example, it's ok to return a list of month names, but not a list of usernames. A good rule of * thumb is that if the adapter data comes from static resources, such data is not PII - see * {@link android.view.ViewStructure#setDataIsSensitive(boolean)} for more info. * * @return {@code null} by default, unless implementations override it. */ default @Nullable CharSequence[] getAutofillOptions() { return null; } }