when we must ensure that only one instance of a class is created and when the instance must be available through all the code. A special care should be taken in multi-threading environments when multiple threads must access the same resources through the same singleton object. Common Usage • Logger Classes • Configuration Classes • Accessing resources in shared mode • Other design patterns implemented as Singletons: Factories and Abstract Factories, Builder, Prototype
vs Lazy Keep in mind • Synchronized • Initialize members when the instance is initialized • Most members shouldn’t have a state • Shouldn’t pass a parameter can have a state (like context) func getEsInstance() *SingletonElasticsearch { onceElasticsearch.Do(func() { instanceElasticsearch = &SingletonElasticsearch{} core.Logger.Infof("getEsInstance() - %s", Config.ElasticSearch.Host) var err error logger := ElasticInfoLogger{} httpClient := &http.Client{ Timeout: time.Second * 3, } optionsFuncs := []elastic.ClientOptionFunc{ elastic.SetURL(Config.ElasticSearch.Host), elastic.SetHealthcheckTimeout(10 * time.Second), elastic.SetSniff(false), elastic.SetErrorLog(logger), elastic.SetHttpClient(httpClient), } instanceElasticsearch.Elasticsearch, err = elastic.NewClient(optionsFuncs...) ... }) return instanceElasticsearch }
when: • a framework delegate the creation of objects derived from a common superclass to the factory • we need flexibility in adding new types of objects that must be created by the class Common Usage Along with singleton pattern the factory is one of the most used patterns. Almost any application has some factories. Here are a some examples in java: • factories providing an xml parser: javax.xml.parsers.DocumentBuilderFactory or javax.xml.parsers.SAXParserFactory • java.net.URLConnection - allows users to decide which protocol to use
• Return type can be a super class or an interface • Don’t pass an argument which is related to return type • If possible, define the presenter constructor as protected or default - Why? public class CampaignPresenterFactory { public static CampaignPresenter<? extends Creative> getPresenter(Context context, Campaign campaign) throws UnsupportedCampaignException { CampaignPresenter<? extends Creative> presenter; switch (campaign.getCreative().getType()) { default: case IMAGE: presenter = new NativeCampaignPresenter(context, campaign, true); break; case NATIVE: presenter = new NativeCampaignPresenter(context, campaign); break; case SDK: presenter = new SdkCampaignPresenter(context, campaign); break; case WEB: case JS: presenter = new WebCampaignPresenter(context, campaign); break; } return presenter; } }
when: • the creation algorithm of a complex object is independent from the parts that actually compose the object • the system needs to allow different representations for the objects that are being built Example • Java ◦ CaptchaResult.java ◦ Usage • Go ◦ EsQueryBuilder.go ◦ Usage
Members shouldn’t be public • Don’t provide setter method in the main class • Return builder itself in order to be a chain public class HttpRequest { private static final String TAG = HttpRequest.class.getSimpleName(); @Expose protected String url; protected String waitString; … protected HttpRequest(Context context) { this.context = context; } public static class Builder { protected HttpRequest httpTask; public Builder(Context context) { httpTask = new HttpRequest(context); if (queue == null) { queue = Volley.newRequestQueue(context); queue.start(); } } public Builder addParam(String key, Object value) { httpTask.params.put(key, String.valueOf(value)); return this; } public Builder setUrl(String url) { httpTask.url = url; return this; } public HttpRequest build() { return httpTask; } } }
when: • the change of a state in one object must be reflected in another object without keeping the objects tight coupled. • the framework we are writing needs to be enhanced in future with new observers with minimal changes. Common Usage • Model View Controller Pattern - The observer pattern is used in the model view controller (MVC) architectural pattern. In MVC the this pattern is used to decouple the model from the view. View represents the Observer and the model is the Observable object. • Event management - This is one of the domains where the Observer patterns is extensively used. Swing and .Net are extensively using the Observer pattern for implementing the events mechanism.
WeakReference if possible • I think map is better than list for observer holders • Always keep in mind that you should write an unregister code right after when you write a register code
when: • When you have a class(Target) that invokes methods defined in an interface and you have a another class(Adapter) that doesn't implement the interface but implements the operations that should be invoked from the first class through the interface. You can change none of the existing code. The adapter will implement the interface and will be the bridge between the 2 classes. • When you write a class (Target) for a generic use relying on some general interfaces and you have some implemented classes, not implementing the interface, that needs to be invoked by the Target class. Common Usage • Non Software Examples of Adapter Patterns : Power Supply Adapters, card readers and adapters, ... • Software Examples of Adapter Patterns: Wrappers used to adopt 3rd parties libraries and frameworks - most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code.
Consider any target class can work with your adapter public abstract class HeaderRecyclerAdapter<VH extends RecyclerView.ViewHolder, H extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected static final int TYPE_HEADER = -2; protected static final int TYPE_ITEM = -1; RecyclerHeader<H> recyclerHeader; public void setRecyclerHeader(RecyclerHeader<H> recyclerHeader) { this.recyclerHeader = recyclerHeader; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder viewHolder; if (isHeaderType(viewType)) { viewHolder = recyclerHeader.onCreateHeaderHolder(parent, viewType); } else { viewHolder = onCreateItemHolder(parent, viewType); } return viewHolder; } protected abstract int getCount(); protected abstract VH onCreateItemHolder(ViewGroup parent, int viewType); protected abstract void onBindItemHolder(VH holder, int position); public interface RecyclerHeader<H> { H onCreateHeaderHolder(ViewGroup parent, int viewType); void onBindHeaderHolder(H holder, int position); } }
logic • DAO - DBMS related • Light model is preferred View • Presentation logic Controller • Select a business logic to process data • Return the result to the view
a logic doesn’t strongly related with API, you should consider to implement the logic in service layer. Unless, you will have a moster controller. (And you might have many duplicated or similar code) buzzscreen/controller/device_v1.go func InitDeviceV1(c *gin.Context) { var deviceReq dto.InitDeviceV1Request err := bindValue(c, &deviceReq) ... device, _ := service.HandleNewDevice(&requestedDevice, c.Request) ... writeJsonSafely(c, http.StatusOK, res) } buzzscreen/controller/device.go func PostDevice(c *gin.Context) { var deviceReq dto.DeviceRequest err := bindValue(c, &deviceReq) ... device, isNewDevice := service.HandleNewDevice(&requestedDevice, c.Request) ... writeJsonSafely(c, http.StatusOK, res) }
Lifecycle perspective ◦ Don’t pass presenter to singleton instance like manager.. • View doesn’t have any reference of presenter ◦ Because you can define different presenters for different models for same view • Event start from View? ◦ Easy to implement (As you can see...) • Events starts from Model? ◦ I recommend to follow observer pattern
in View or Model • Before write a code in presenter, think one more whether it can be done in view or model layer. It will keep the presenter tidy and prevent view and model from becoming empty • What can we do with a monster presenter? public class TicTacToePresenter implements Board.EventListener, TicTacToeView.EventListener { private TicTacToeView view; private Board model; // Define event listeners here. You can still write a view structure related code in View classes. But all logics of view should be here. public TicTacToePresenter(TicTacToeView view) { this.view = view; this.model = new Board(); this.model.addEventListener(this); } @Override public void finalize() { // This is optional this.model.removeEventListener(this); } @Override public void onBoardChanged(Board model) { // Update view } // When the user selects a cell, our presenter only hears about what was (row, col) pressed, it's up to the view now to determine that from the Button that was pressed. @Override public void onButtonSelected(int row, int col) { Player playerThatMoved = model.mark(row, col); if(playerThatMoved != null) { view.setButtonText(row, col, playerThatMoved.toString()); if (model.getWinner() != null) { view.showWinner(playerThatMoved.toString()); } } } }
should be a WeakReferenceMap ◦ Otherwise, you will have a memory leak public class Board { WeakReferenceMap<Object, EventListener> listeners = new WeakReferenceMap<> public void addListener(EventListener listener) { if (listeners.contains(listener) == false) { listeners.put(listener, listener); } } public void removeListener(EventListener listener) { if (listeners.contains(listener)) { listeners.remove(listener); } } … }
◦ There should be a way to prevent it. If it is not? let’s find what make it impossible and refactor it. • How to manage packages? ◦ Package by component - Activity / Service / EventReceiver ... ◦ Package by feature - Feed / Store / Ad / Content … ◦ Package by feature is preferred
50 lines. ◦ A function should be shown without a scroll. ◦ Don’t make a class with more than 1000 lines. ◦ The function name should represent all work done inside the function. • Don’t use static keyword w/o final ◦ Why? It is hard to follow where to initialize or update the field (ServerConfig.java) ◦ All static field w/o final can be written in Singleton design pattern • Think one more before creating xxManager and xxUtils ◦ Controller & Manager & Handler